//===--- Refactoring.cpp ---------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "polarphp/ide/Refactoring.h"
#include "polarphp/ide/IDERequests.h"
#include "polarphp/ast/AstContext.h"
#include "polarphp/ast/AstPrinter.h"
#include "polarphp/ast/Decl.h"
#include "polarphp/ast/DiagnosticsRefactoring.h"
#include "polarphp/ast/Expr.h"
#include "polarphp/ast/NameLookup.h"
#include "polarphp/ast/Pattern.h"
#include "polarphp/ast/InterfaceConformance.h"
#include "polarphp/ast/Stmt.h"
#include "polarphp/ast/Types.h"
#include "polarphp/ast/UsrGeneration.h"
#include "polarphp/basic/Edit.h"
#include "polarphp/basic/StringExtras.h"
#include "polarphp/frontend/Frontend.h"
#include "polarphp/index/Index.h"
#include "polarphp/llparser/Lexer.h"
#include "polarphp/sema/IDETypeChecking.h"
#include "polarphp/global/Subsystems.h"
#include "clang/Rewrite/Core/RewriteBuffer.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/SmallPtrSet.h"

using namespace polar;
using namespace polar::ide;
using namespace polar::index;
using namespace polar::llparser;

namespace {
class ContextFinder : public SourceEntityWalker {
   SourceFile &SF;
   AstContext &Ctx;
   SourceManager &SM;
   SourceRange Target;
   llvm::function_ref<bool(AstNode)> IsContext;
   SmallVector<AstNode, 4> AllContexts;
   bool contains(AstNode Enclosing) {
      auto Result = SM.rangeContains(Enclosing.getSourceRange(), Target);
      if (Result && IsContext(Enclosing))
         AllContexts.push_back(Enclosing);
      return Result;
   }
public:
   ContextFinder(SourceFile &SF, AstNode TargetNode,
                 llvm::function_ref<bool(AstNode)> IsContext =
                 [](AstNode N) { return true; }) :
      SF(SF), Ctx(SF.getAstContext()), SM(Ctx.SourceMgr),
      Target(TargetNode.getSourceRange()), IsContext(IsContext) {}
   ContextFinder(SourceFile &SF, SourceLoc TargetLoc,
                 llvm::function_ref<bool(AstNode)> IsContext =
                 [](AstNode N) { return true; }) :
      SF(SF), Ctx(SF.getAstContext()), SM(Ctx.SourceMgr),
      Target(TargetLoc), IsContext(IsContext) {
      assert(TargetLoc.isValid() && "Invalid loc to find");
   }
   bool walkToDeclPre(Decl *D, CharSourceRange Range) override { return contains(D); }
   bool walkToStmtPre(Stmt *S) override { return contains(S); }
   bool walkToExprPre(Expr *E) override { return contains(E); }
   void resolve() { walk(SF); }
   llvm::ArrayRef<AstNode> getContexts() const {
      return llvm::makeArrayRef(AllContexts);
   }
};

class Renamer {
protected:
   const SourceManager &SM;

protected:
   Renamer(const SourceManager &SM, StringRef OldName) : SM(SM), Old(OldName) {}

   // Implementor's interface.
   virtual void doRenameLabel(CharSourceRange Label,
                              RefactoringRangeKind RangeKind,
                              unsigned NameIndex) = 0;
   virtual void doRenameBase(CharSourceRange Range,
                             RefactoringRangeKind RangeKind) = 0;

public:
   const DeclNameViewer Old;

public:
   virtual ~Renamer() {}

   /// Adds a replacement to rename the given base name range
   /// \return true if the given range does not match the old name
   bool renameBase(CharSourceRange Range, RefactoringRangeKind RangeKind) {
      assert(Range.isValid());

      StringRef Existing = Range.str();
      if (Existing != Old.base())
         return true;
      doRenameBase(Range, RangeKind);
      return false;
   }

   /// Adds replacements to rename the given label ranges
   /// \return true if the label ranges do not match the old name
   bool renameLabels(ArrayRef<CharSourceRange> LabelRanges,
                     LabelRangeType RangeType, bool isCallSite) {
      if (isCallSite)
         return renameLabelsLenient(LabelRanges, RangeType);

      ArrayRef<StringRef> OldLabels = Old.args();

      if (OldLabels.size() != LabelRanges.size())
         return true;

      size_t Index = 0;
      for (const auto &LabelRange : LabelRanges) {
         assert(LabelRange.isValid());
         if (!labelRangeMatches(LabelRange, RangeType, OldLabels[Index]))
            return true;
         splitAndRenameLabel(LabelRange, RangeType, Index++);
      }
      return false;
   }

   bool isOperator() const { return Lexer::isOperator(Old.base()); }

private:
   void splitAndRenameLabel(CharSourceRange Range, LabelRangeType RangeType,
                            size_t NameIndex) {
      switch (RangeType) {
         case LabelRangeType::CallArg:
            return splitAndRenameCallArg(Range, NameIndex);
         case LabelRangeType::Param:
            return splitAndRenameParamLabel(Range, NameIndex, /*IsCollapsible=*/true);
         case LabelRangeType::NoncollapsibleParam:
            return splitAndRenameParamLabel(Range, NameIndex, /*IsCollapsible=*/false);
         case LabelRangeType::Selector:
            return doRenameLabel(
               Range, RefactoringRangeKind::SelectorArgumentLabel, NameIndex);
         case LabelRangeType::None:
            llvm_unreachable("expected a label range");
      }
   }

   void splitAndRenameParamLabel(CharSourceRange Range, size_t NameIndex, bool IsCollapsible) {
      // Split parameter range foo([a b]: Int) into decl argument label [a] and
      // parameter name [b] or noncollapsible parameter name [b] if IsCollapsible
      // is false (as for subscript decls). If we have only foo([a]: Int), then we
      // add an empty range for the local name, or for the decl argument label if
      // IsCollapsible is false.
      StringRef Content = Range.str();
      size_t ExternalNameEnd = Content.find_first_of(" \t\n\v\f\r/");

      if (ExternalNameEnd == StringRef::npos) { // foo([a]: Int)
         if (IsCollapsible) {
            doRenameLabel(Range, RefactoringRangeKind::DeclArgumentLabel, NameIndex);
            doRenameLabel(CharSourceRange{Range.getEnd(), 0},
                          RefactoringRangeKind::ParameterName, NameIndex);
         } else {
            doRenameLabel(CharSourceRange{Range.getStart(), 0},
                          RefactoringRangeKind::DeclArgumentLabel, NameIndex);
            doRenameLabel(Range, RefactoringRangeKind::NoncollapsibleParameterName,
                          NameIndex);
         }
      } else { // foo([a b]: Int)
         CharSourceRange Ext{Range.getStart(), unsigned(ExternalNameEnd)};

         // Note: we consider the leading whitespace part of the parameter name
         // if the parameter is collapsible, since if the parameter is collapsed
         // into a matching argument label, we want to remove the whitespace too.
         // FIXME: handle comments foo(a /*...*/b: Int).
         size_t LocalNameStart = Content.find_last_of(" \t\n\v\f\r/");
         assert(LocalNameStart != StringRef::npos);
         if (!IsCollapsible)
            ++LocalNameStart;
         auto LocalLoc = Range.getStart().getAdvancedLocOrInvalid(LocalNameStart);
         CharSourceRange Local{LocalLoc, unsigned(Content.size() - LocalNameStart)};

         doRenameLabel(Ext, RefactoringRangeKind::DeclArgumentLabel, NameIndex);
         if (IsCollapsible) {
            doRenameLabel(Local, RefactoringRangeKind::ParameterName, NameIndex);
         } else {
            doRenameLabel(Local, RefactoringRangeKind::NoncollapsibleParameterName, NameIndex);
         }
      }
   }

   void splitAndRenameCallArg(CharSourceRange Range, size_t NameIndex) {
      // Split call argument foo([a: ]1) into argument name [a] and the remainder
      // [: ].
      StringRef Content = Range.str();
      size_t Colon = Content.find(':'); // FIXME: leading whitespace?
      if (Colon == StringRef::npos) {
         assert(Content.empty());
         doRenameLabel(Range, RefactoringRangeKind::CallArgumentCombined,
                       NameIndex);
         return;
      }

      // Include any whitespace before the ':'.
      assert(Colon == Content.substr(0, Colon).size());
      Colon = Content.substr(0, Colon).rtrim().size();

      CharSourceRange Arg{Range.getStart(), unsigned(Colon)};
      doRenameLabel(Arg, RefactoringRangeKind::CallArgumentLabel, NameIndex);

      auto ColonLoc = Range.getStart().getAdvancedLocOrInvalid(Colon);
      assert(ColonLoc.isValid());
      CharSourceRange Rest{ColonLoc, unsigned(Content.size() - Colon)};
      doRenameLabel(Rest, RefactoringRangeKind::CallArgumentColon, NameIndex);
   }

   bool labelRangeMatches(CharSourceRange Range, LabelRangeType RangeType, StringRef Expected) {
      if (Range.getByteLength()) {
         CharSourceRange ExistingLabelRange =
            Lexer::getCharSourceRangeFromSourceRange(SM, Range.getStart());
         StringRef ExistingLabel = ExistingLabelRange.str();

         switch (RangeType) {
            case LabelRangeType::NoncollapsibleParam:
               if (ExistingLabelRange == Range && Expected.empty()) // subscript([x]: Int)
                  return true;
               LLVM_FALLTHROUGH;
            case LabelRangeType::CallArg:
            case LabelRangeType::Param:
            case LabelRangeType::Selector:
               return ExistingLabel == (Expected.empty() ? "_" : Expected);
            case LabelRangeType::None:
               llvm_unreachable("Unhandled label range type");
         }
      }
      return Expected.empty();
   }

   bool renameLabelsLenient(ArrayRef<CharSourceRange> LabelRanges,
                            LabelRangeType RangeType) {

      ArrayRef<StringRef> OldNames = Old.args();

      size_t NameIndex = 0;

      for (CharSourceRange Label : LabelRanges) {
         // empty label
         if (!Label.getByteLength()) {

            // first name pos
            if (!NameIndex) {
               while (!OldNames[NameIndex].empty()) {
                  if (++NameIndex >= OldNames.size())
                     return true;
               }
               splitAndRenameLabel(Label, RangeType, NameIndex++);
               continue;
            }

            // other name pos
            if (NameIndex >= OldNames.size() || !OldNames[NameIndex].empty()) {
               // FIXME: only allow one variadic param
               continue; // allow for variadic
            }
            splitAndRenameLabel(Label, RangeType, NameIndex++);
            continue;
         }

         // non-empty label
         if (NameIndex >= OldNames.size())
            return true;

         while (!labelRangeMatches(Label, RangeType, OldNames[NameIndex])) {
            if (++NameIndex >= OldNames.size())
               return true;
         };
         splitAndRenameLabel(Label, RangeType, NameIndex++);
      }
      return false;
   }

   static RegionType getSyntacticRenameRegionType(const ResolvedLoc &Resolved) {
      if (Resolved.Node.isNull())
         return RegionType::Comment;

      if (Expr *E = Resolved.Node.getAsExpr()) {
         if (isa<StringLiteralExpr>(E))
            return RegionType::String;
      }
      if (Resolved.IsInSelector)
         return RegionType::Selector;
      if (Resolved.IsActive)
         return RegionType::ActiveCode;
      return RegionType::InactiveCode;
   }

public:
   RegionType addSyntacticRenameRanges(const ResolvedLoc &Resolved,
                                       const RenameLoc &Config) {

      if (!Resolved.Range.isValid())
         return RegionType::Unmatched;

      auto RegionKind = getSyntacticRenameRegionType(Resolved);
      // Don't include unknown references coming from active code; if we don't
      // have a semantic NameUsage for them, then they're likely unrelated symbols
      // that happen to have the same name.
      if (RegionKind == RegionType::ActiveCode &&
          Config.Usage == NameUsage::Unknown)
         return RegionType::Unmatched;

      assert(Config.Usage != NameUsage::Call || Config.IsFunctionLike);

      // FIXME: handle escaped keyword names `init`
      bool IsSubscript = Old.base() == "subscript" && Config.IsFunctionLike;
      bool IsInit = Old.base() == "init" && Config.IsFunctionLike;
      bool IsKeywordBase = IsInit || IsSubscript;

      // Filter out non-semantic keyword basename locations with no labels.
      // We've already filtered out those in active code, so these are
      // any appearance of just 'init' or 'subscript' in strings, comments, and
      // inactive code.
      if (IsKeywordBase && (Config.Usage == NameUsage::Unknown &&
                            Resolved.LabelType == LabelRangeType::None))
         return RegionType::Unmatched;

      if (!Config.IsFunctionLike || !IsKeywordBase) {
         if (renameBase(Resolved.Range, RefactoringRangeKind::BaseName))
            return RegionType::Mismatch;

      } else if (IsKeywordBase && Config.Usage == NameUsage::Definition) {
         if (renameBase(Resolved.Range, RefactoringRangeKind::KeywordBaseName))
            return RegionType::Mismatch;
      }

      bool HandleLabels = false;
      if (Config.IsFunctionLike) {
         switch (Config.Usage) {
            case NameUsage::Call:
               HandleLabels = !isOperator();
               break;
            case NameUsage::Definition:
               HandleLabels = true;
               break;
            case NameUsage::Reference:
               HandleLabels = Resolved.LabelType == LabelRangeType::Selector || IsSubscript;
               break;
            case NameUsage::Unknown:
               HandleLabels = Resolved.LabelType != LabelRangeType::None;
               break;
         }
      } else if (Resolved.LabelType != LabelRangeType::None &&
                 !Config.IsNonInterfaceType &&
                 // FIXME: Workaround for enum case labels until we support them
                 Config.Usage != NameUsage::Definition) {
         return RegionType::Mismatch;
      }

      if (HandleLabels) {
         bool isCallSite = Config.Usage != NameUsage::Definition &&
                           (Config.Usage != NameUsage::Reference || IsSubscript) &&
                           Resolved.LabelType == LabelRangeType::CallArg;

         if (renameLabels(Resolved.LabelRanges, Resolved.LabelType, isCallSite))
            return Config.Usage == NameUsage::Unknown ?
                   RegionType::Unmatched : RegionType::Mismatch;
      }

      return RegionKind;
   }
};

class RenameRangeDetailCollector : public Renamer {
   void doRenameLabel(CharSourceRange Label, RefactoringRangeKind RangeKind,
                      unsigned NameIndex) override {
      Ranges.push_back({Label, RangeKind, NameIndex});
   }
   void doRenameBase(CharSourceRange Range,
                     RefactoringRangeKind RangeKind) override {
      Ranges.push_back({Range, RangeKind, None});
   }

public:
   RenameRangeDetailCollector(const SourceManager &SM, StringRef OldName)
      : Renamer(SM, OldName) {}
   std::vector<RenameRangeDetail> Ranges;
};

class TextReplacementsRenamer : public Renamer {
   llvm::StringSet<> &ReplaceTextContext;
   std::vector<Replacement> Replacements;

public:
   const DeclNameViewer New;

private:
   StringRef registerText(StringRef Text) {
      if (Text.empty())
         return Text;
      return ReplaceTextContext.insert(Text).first->getKey();
   }

   StringRef getCallArgLabelReplacement(StringRef OldLabelRange,
                                        StringRef NewLabel) {
      return NewLabel.empty() ? "" : NewLabel;
   }

   StringRef getCallArgColonReplacement(StringRef OldLabelRange,
                                        StringRef NewLabel) {
      // Expected OldLabelRange: foo( []3, a[: ]2,  b[ : ]3 ...)
      // FIXME: Preserve comments: foo([a/*:*/ : /*:*/ ]2, ...)
      if (NewLabel.empty())
         return "";
      if (OldLabelRange.empty())
         return ": ";
      return registerText(OldLabelRange);
   }

   StringRef getCallArgCombinedReplacement(StringRef OldArgLabel,
                                           StringRef NewArgLabel) {
      // This case only happens when going from foo([]1) to foo([a: ]1).
      assert(OldArgLabel.empty());
      if (NewArgLabel.empty())
         return "";
      return registerText((llvm::Twine(NewArgLabel) + ": ").str());
   }

   StringRef getParamNameReplacement(StringRef OldParam, StringRef OldArgLabel,
                                     StringRef NewArgLabel) {
      // We don't want to get foo(a a: Int), so drop the parameter name if the
      // argument label will match the original name.
      // Note: the leading whitespace is part of the parameter range.
      if (!NewArgLabel.empty() && OldParam.ltrim() == NewArgLabel)
         return "";

      // If we're renaming foo(x: Int) to foo(_:), then use the original argument
      // label as the parameter name so as to not break references in the body.
      if (NewArgLabel.empty() && !OldArgLabel.empty() && OldParam.empty())
         return registerText((llvm::Twine(" ") + OldArgLabel).str());

      return registerText(OldParam);
   }

   StringRef getDeclArgumentLabelReplacement(StringRef OldLabelRange,
                                             StringRef NewArgLabel) {
      // OldLabelRange is subscript([]a: Int), foo([a]: Int) or foo([a] b: Int)
      if (NewArgLabel.empty())
         return OldLabelRange.empty() ? "" : "_";

      if (OldLabelRange.empty())
         return registerText((llvm::Twine(NewArgLabel) + " ").str());
      return registerText(NewArgLabel);
   }

   StringRef getReplacementText(StringRef LabelRange,
                                RefactoringRangeKind RangeKind,
                                StringRef OldLabel, StringRef NewLabel) {
      switch (RangeKind) {
         case RefactoringRangeKind::CallArgumentLabel:
            return getCallArgLabelReplacement(LabelRange, NewLabel);
         case RefactoringRangeKind::CallArgumentColon:
            return getCallArgColonReplacement(LabelRange, NewLabel);
         case RefactoringRangeKind::CallArgumentCombined:
            return getCallArgCombinedReplacement(LabelRange, NewLabel);
         case RefactoringRangeKind::ParameterName:
            return getParamNameReplacement(LabelRange, OldLabel, NewLabel);
         case RefactoringRangeKind::NoncollapsibleParameterName:
            return LabelRange;
         case RefactoringRangeKind::DeclArgumentLabel:
            return getDeclArgumentLabelReplacement(LabelRange, NewLabel);
         case RefactoringRangeKind::SelectorArgumentLabel:
            return NewLabel.empty() ? "_" : registerText(NewLabel);
         default:
            llvm_unreachable("label range type is none but there are labels");
      }
   }

   void addReplacement(CharSourceRange LabelRange,
                       RefactoringRangeKind RangeKind, StringRef OldLabel,
                       StringRef NewLabel) {
      StringRef ExistingLabel = LabelRange.str();
      StringRef Text =
         getReplacementText(ExistingLabel, RangeKind, OldLabel, NewLabel);
      if (Text != ExistingLabel)
         Replacements.push_back({LabelRange, Text, {}});
   }

   void doRenameLabel(CharSourceRange Label, RefactoringRangeKind RangeKind,
                      unsigned NameIndex) override {
      addReplacement(Label, RangeKind, Old.args()[NameIndex],
                     New.args()[NameIndex]);
   }

   void doRenameBase(CharSourceRange Range, RefactoringRangeKind) override {
      if (Old.base() != New.base())
         Replacements.push_back({Range, registerText(New.base()), {}});
   }

public:
   TextReplacementsRenamer(const SourceManager &SM, StringRef OldName,
                           StringRef NewName,
                           llvm::StringSet<> &ReplaceTextContext)
      : Renamer(SM, OldName), ReplaceTextContext(ReplaceTextContext),
        New(NewName) {
      assert(Old.isValid() && New.isValid());
      assert(Old.partsCount() == New.partsCount());
   }

   std::vector<Replacement> getReplacements() const {
      return std::move(Replacements);
   }
};

static const ValueDecl *getRelatedSystemDecl(const ValueDecl *VD) {
   if (VD->getModuleContext()->isSystemModule())
      return VD;
   for (auto *Req : VD->getSatisfiedInterfaceRequirements()) {
      if (Req->getModuleContext()->isSystemModule())
         return Req;
   }
   for (auto Over = VD->getOverriddenDecl(); Over;
        Over = Over->getOverriddenDecl()) {
      if (Over->getModuleContext()->isSystemModule())
         return Over;
   }
   return nullptr;
}

static Optional<RefactoringKind> getAvailableRenameForDecl(const ValueDecl *VD) {
   std::vector<RenameAvailabiliyInfo> Scratch;
   for (auto &Info : collectRenameAvailabilityInfo(VD, Scratch)) {
      if (Info.AvailableKind == RenameAvailableKind::Available)
         return Info.Kind;
   }
   return None;
}

class RenameRangeCollector : public IndexDataConsumer {
public:
   RenameRangeCollector(StringRef USR, StringRef newName)
      : USR(USR.str()), newName(newName.str()) {}

   RenameRangeCollector(const ValueDecl *D, StringRef newName)
      : newName(newName.str()) {
      llvm::raw_string_ostream OS(USR);
      printValueDeclUSR(D, OS);
   }

   ArrayRef<RenameLoc> results() const { return locations; }

private:
   bool indexLocals() override { return true; }
   void failed(StringRef error) override {}
   bool startDependency(StringRef name, StringRef path, bool isClangModule, bool isSystem) override {
      return true;
   }
   bool finishDependency(bool isClangModule) override { return true; }

   Action startSourceEntity(const IndexSymbol &symbol) override {
      if (symbol.USR == USR) {
         if (auto loc = indexSymbolToRenameLoc(symbol, newName)) {
            locations.push_back(std::move(*loc));
         }
      }
      return IndexDataConsumer::Continue;
   }

   bool finishSourceEntity(SymbolInfo symInfo, SymbolRoleSet roles) override {
      return true;
   }

   Optional<RenameLoc> indexSymbolToRenameLoc(const index::IndexSymbol &symbol,
                                              StringRef NewName);

private:
   std::string USR;
   std::string newName;
   StringScratchSpace stringStorage;
   std::vector<RenameLoc> locations;
};

Optional<RenameLoc>
RenameRangeCollector::indexSymbolToRenameLoc(const index::IndexSymbol &symbol,
                                             StringRef newName) {
   if (symbol.roles & (unsigned)index::SymbolRole::Implicit) {
      return None;
   }

   NameUsage usage = NameUsage::Unknown;
   if (symbol.roles & (unsigned)index::SymbolRole::Call) {
      usage = NameUsage::Call;
   } else if (symbol.roles & (unsigned)index::SymbolRole::Definition) {
      usage = NameUsage::Definition;
   } else if (symbol.roles & (unsigned)index::SymbolRole::Reference) {
      usage = NameUsage::Reference;
   } else {
      llvm_unreachable("unexpected role");
   }

   bool isFunctionLike = false;
   bool isNonInterfaceType = false;

   switch (symbol.symInfo.Kind) {
      case index::SymbolKind::EnumConstant:
      case index::SymbolKind::Function:
      case index::SymbolKind::Constructor:
      case index::SymbolKind::ConversionFunction:
      case index::SymbolKind::InstanceMethod:
      case index::SymbolKind::ClassMethod:
      case index::SymbolKind::StaticMethod:
         isFunctionLike = true;
         break;
      case index::SymbolKind::Class:
      case index::SymbolKind::Enum:
      case index::SymbolKind::Struct:
         isNonInterfaceType = true;
         break;
      default:
         break;
   }
   StringRef oldName = stringStorage.copyString(symbol.name);
   return RenameLoc{symbol.line,    symbol.column,    usage, oldName, newName,
                    isFunctionLike, isNonInterfaceType};
}

ArrayRef<SourceFile*>
collectSourceFiles(ModuleDecl *MD, llvm::SmallVectorImpl<SourceFile*> &Scratch) {
   for (auto Unit : MD->getFiles()) {
      if (auto SF = dyn_cast<SourceFile>(Unit)) {
         Scratch.push_back(SF);
      }
   }
   return llvm::makeArrayRef(Scratch);
}

/// Get the source file that contains the given range and belongs to the module.
SourceFile *getContainingFile(ModuleDecl *M, RangeConfig Range) {
   llvm::SmallVector<SourceFile*, 4> Files;
   for (auto File : collectSourceFiles(M, Files)) {
      if (File->getBufferID()) {
         if (File->getBufferID().getValue() == Range.BufferId) {
            return File;
         }
      }
   }
   return nullptr;
}

class RefactoringAction {
protected:
   ModuleDecl *MD;
   SourceFile *TheFile;
   SourceEditConsumer &EditConsumer;
   AstContext &Ctx;
   SourceManager &SM;
   DiagnosticEngine DiagEngine;
   SourceLoc StartLoc;
   StringRef PreferredName;
public:
   RefactoringAction(ModuleDecl *MD, RefactoringOptions &Opts,
                     SourceEditConsumer &EditConsumer,
                     DiagnosticConsumer &DiagConsumer);
   virtual ~RefactoringAction() = default;
   virtual bool performChange() = 0;
};

RefactoringAction::
RefactoringAction(ModuleDecl *MD, RefactoringOptions &Opts,
                  SourceEditConsumer &EditConsumer,
                  DiagnosticConsumer &DiagConsumer): MD(MD),
                                                     TheFile(getContainingFile(MD, Opts.Range)),
                                                     EditConsumer(EditConsumer), Ctx(MD->getAstContext()),
                                                     SM(MD->getAstContext().SourceMgr), DiagEngine(SM),
                                                     StartLoc(Lexer::getLocForStartOfToken(SM, Opts.Range.getStart(SM))),
                                                     PreferredName(Opts.PreferredName) {
   DiagEngine.addConsumer(DiagConsumer);
}

/// Different from RangeBasedRefactoringAction, TokenBasedRefactoringAction takes
/// the input of a given token, e.g., a name or an "if" key word. Contextual
/// refactoring kinds can suggest applicable refactorings on that token, e.g.
/// rename or reverse if statement.
class TokenBasedRefactoringAction : public RefactoringAction {
protected:
   ResolvedCursorInfo CursorInfo;
public:
   TokenBasedRefactoringAction(ModuleDecl *MD, RefactoringOptions &Opts,
                               SourceEditConsumer &EditConsumer,
                               DiagnosticConsumer &DiagConsumer) :
      RefactoringAction(MD, Opts, EditConsumer, DiagConsumer) {
      // Resolve the sema token and save it for later use.
      CursorInfo = evaluateOrDefault(TheFile->getAstContext().evaluator,
                                     CursorInfoRequest{ CursorInfoOwner(TheFile, StartLoc)},
                                     ResolvedCursorInfo());
   }
};

#define CURSOR_REFACTORING(KIND, NAME, ID)                                    \
class RefactoringAction##KIND: public TokenBasedRefactoringAction {           \
  public:                                                                     \
  RefactoringAction##KIND(ModuleDecl *MD, RefactoringOptions &Opts,           \
                          SourceEditConsumer &EditConsumer,                   \
                          DiagnosticConsumer &DiagConsumer) :                 \
    TokenBasedRefactoringAction(MD, Opts, EditConsumer, DiagConsumer) {}      \
  bool performChange() override;                                              \
  static bool isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag);   \
  bool isApplicable() {                                                       \
    return RefactoringAction##KIND::isApplicable(CursorInfo, DiagEngine) ;    \
  }                                                                           \
};
#include "polarphp/ide/RefactoringKindsDef.h"

class RangeBasedRefactoringAction : public RefactoringAction {
protected:
   ResolvedRangeInfo RangeInfo;
public:
   RangeBasedRefactoringAction(ModuleDecl *MD, RefactoringOptions &Opts,
                               SourceEditConsumer &EditConsumer,
                               DiagnosticConsumer &DiagConsumer) :
      RefactoringAction(MD, Opts, EditConsumer, DiagConsumer),
      RangeInfo(evaluateOrDefault(MD->getAstContext().evaluator,
                                  RangeInfoRequest(RangeInfoOwner(TheFile, Opts.Range.getStart(SM), Opts.Range.getEnd(SM))),
                                  ResolvedRangeInfo())) {}
};

#define RANGE_REFACTORING(KIND, NAME, ID)                                     \
class RefactoringAction##KIND: public RangeBasedRefactoringAction {           \
  public:                                                                     \
  RefactoringAction##KIND(ModuleDecl *MD, RefactoringOptions &Opts,           \
                          SourceEditConsumer &EditConsumer,                   \
                          DiagnosticConsumer &DiagConsumer) :                 \
    RangeBasedRefactoringAction(MD, Opts, EditConsumer, DiagConsumer) {}      \
  bool performChange() override;                                              \
  static bool isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag);   \
  bool isApplicable() {                                                       \
    return RefactoringAction##KIND::isApplicable(RangeInfo, DiagEngine) ;     \
  }                                                                           \
};
#include "polarphp/ide/RefactoringKindsDef.h"

bool RefactoringActionLocalRename::
isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &Diag) {
   if (CursorInfo.Kind != CursorInfoKind::ValueRef)
      return false;
   auto RenameOp = getAvailableRenameForDecl(CursorInfo.ValueD);
   return RenameOp.hasValue() &&
          RenameOp.getValue() == RefactoringKind::LocalRename;
}

static void analyzeRenameScope(ValueDecl *VD, DiagnosticEngine &Diags,
                               llvm::SmallVectorImpl<DeclContext *> &Scopes) {
   Scopes.clear();
   if (!getAvailableRenameForDecl(VD).hasValue()) {
      Diags.diagnose(SourceLoc(), diag::value_decl_no_loc, VD->getFullName());
      return;
   }

   auto *Scope = VD->getDeclContext();
   // If the context is a top-level code decl, there may be other sibling
   // decls that the renamed symbol is visible from
   if (isa<TopLevelCodeDecl>(Scope))
      Scope = Scope->getParent();

   Scopes.push_back(Scope);
}

bool RefactoringActionLocalRename::performChange() {
   if (StartLoc.isInvalid()) {
      DiagEngine.diagnose(SourceLoc(), diag::invalid_location);
      return true;
   }
   if (!DeclNameViewer(PreferredName).isValid()) {
      DiagEngine.diagnose(SourceLoc(), diag::invalid_name, PreferredName);
      return true;
   }
   if (!TheFile) {
      DiagEngine.diagnose(StartLoc, diag::location_module_mismatch,
                          MD->getNameStr());
      return true;
   }
   CursorInfo = evaluateOrDefault(TheFile->getAstContext().evaluator,
                                  CursorInfoRequest{CursorInfoOwner(TheFile, StartLoc)},
                                  ResolvedCursorInfo());
   if (CursorInfo.isValid() && CursorInfo.ValueD) {
      ValueDecl *VD = CursorInfo.CtorTyRef ? CursorInfo.CtorTyRef : CursorInfo.ValueD;
      llvm::SmallVector<DeclContext *, 8> Scopes;
      analyzeRenameScope(VD, DiagEngine, Scopes);
      if (Scopes.empty())
         return true;
      RenameRangeCollector rangeCollector(VD, PreferredName);
      for (DeclContext *DC : Scopes)
         indexDeclContext(DC, rangeCollector);

      auto consumers = DiagEngine.takeConsumers();
      assert(consumers.size() == 1);
      return syntacticRename(TheFile, rangeCollector.results(), EditConsumer,
                             *consumers[0]);
   } else {
      DiagEngine.diagnose(StartLoc, diag::unresolved_location);
      return true;
   }
}

StringRef getDefaultPreferredName(RefactoringKind Kind) {
   switch(Kind) {
      case RefactoringKind::None:
         llvm_unreachable("Should be a valid refactoring kind");
      case RefactoringKind::GlobalRename:
      case RefactoringKind::LocalRename:
         return "newName";
      case RefactoringKind::ExtractExpr:
      case RefactoringKind::ExtractRepeatedExpr:
         return "extractedExpr";
      case RefactoringKind::ExtractFunction:
         return "extractedFunc";
      default:
         return "";
   }
}

enum class CannotExtractReason {
   Literal,
   VoidType,
};

class ExtractCheckResult {
   bool KnownFailure;
   llvm::SmallVector<CannotExtractReason, 2> AllReasons;

public:
   ExtractCheckResult(): KnownFailure(true) {}
   ExtractCheckResult(ArrayRef<CannotExtractReason> AllReasons):
      KnownFailure(false), AllReasons(AllReasons.begin(), AllReasons.end()) {}
   bool success() { return success({}); }
   bool success(llvm::ArrayRef<CannotExtractReason> ExpectedReasons) {
      if (KnownFailure)
         return false;
      bool Result = true;

      // Check if any reasons aren't covered by the list of expected reasons
      // provided by the client.
      for (auto R: AllReasons) {
         Result &= llvm::is_contained(ExpectedReasons, R);
      }
      return Result;
   }
};

/// Check whether a given range can be extracted.
/// Return true on successful condition checking,.
/// Return false on failed conditions.
ExtractCheckResult checkExtractConditions(ResolvedRangeInfo &RangeInfo,
                                          DiagnosticEngine &DiagEngine) {
   llvm::SmallVector<CannotExtractReason, 2> AllReasons;
   // If any declared declaration is refered out of the given range, return false.
   auto Declared = RangeInfo.DeclaredDecls;
   auto It = std::find_if(Declared.begin(), Declared.end(),
                          [](DeclaredDecl DD) { return DD.ReferredAfterRange; });
   if (It != Declared.end()) {
      DiagEngine.diagnose(It->VD->getLoc(),
                          diag::value_decl_referenced_out_of_range,
                          It->VD->getFullName());
      return ExtractCheckResult();
   }

   // We cannot extract a range with multi entry points.
   if (!RangeInfo.HasSingleEntry) {
      DiagEngine.diagnose(SourceLoc(), diag::multi_entry_range);
      return ExtractCheckResult();
   }

   // We cannot extract code that is not sure to exit or not.
   if (RangeInfo.exit() == ExitState::Unsure) {
      return ExtractCheckResult();
   }

   // We cannot extract expressions of l-value type.
   if (auto Ty = RangeInfo.getType()) {
      if (Ty->hasLValueType() || Ty->is<InOutType>())
         return ExtractCheckResult();

      // Disallow extracting error type expressions/statements
      // FIXME: diagnose what happened?
      if (Ty->hasError())
         return ExtractCheckResult();

      if (Ty->isVoid()) {
         AllReasons.emplace_back(CannotExtractReason::VoidType);
      }
   }

   // We cannot extract a range with orphaned loop keyword.
   switch (RangeInfo.Orphan) {
      case polar::ide::OrphanKind::Continue:
         DiagEngine.diagnose(SourceLoc(), diag::orphan_loop_keyword, "continue");
         return ExtractCheckResult();
      case polar::ide::OrphanKind::Break:
         DiagEngine.diagnose(SourceLoc(), diag::orphan_loop_keyword, "break");
         return ExtractCheckResult();
      case polar::ide::OrphanKind::None:
         break;
   }

   // Guard statement can not be extracted.
   if (llvm::any_of(RangeInfo.ContainedNodes,
                    [](AstNode N) { return N.isStmt(StmtKind::Guard); })) {
      return ExtractCheckResult();
   }

   // Disallow extracting certain kinds of statements.
   if (RangeInfo.Kind == RangeKind::SingleStatement) {
      Stmt *S = RangeInfo.ContainedNodes[0].get<Stmt *>();

      // These aren't independent statement.
      if (isa<BraceStmt>(S) || isa<CatchStmt>(S) || isa<CaseStmt>(S))
         return ExtractCheckResult();
   }

   // Disallow extracting literals.
   if (RangeInfo.Kind == RangeKind::SingleExpression) {
      Expr *E = RangeInfo.ContainedNodes[0].get<Expr*>();

      // Until implementing the performChange() part of extracting trailing
      // closures, we disable them for now.
      if (isa<AbstractClosureExpr>(E))
         return ExtractCheckResult();

      if (isa<LiteralExpr>(E))
         AllReasons.emplace_back(CannotExtractReason::Literal);
   }

   switch (RangeInfo.RangeContext->getContextKind()) {
      case polar::DeclContextKind::Initializer:
      case polar::DeclContextKind::SubscriptDecl:
      case polar::DeclContextKind::EnumElementDecl:
      case polar::DeclContextKind::AbstractFunctionDecl:
      case polar::DeclContextKind::AbstractClosureExpr:
      case polar::DeclContextKind::TopLevelCodeDecl:
         break;

      case polar::DeclContextKind::SerializedLocal:
      case polar::DeclContextKind::Module:
      case polar::DeclContextKind::FileUnit:
      case polar::DeclContextKind::GenericTypeDecl:
      case polar::DeclContextKind::ExtensionDecl:
         return ExtractCheckResult();
   }
   return ExtractCheckResult(AllReasons);
}

bool RefactoringActionExtractFunction::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   switch (Info.Kind) {
      case RangeKind::PartOfExpression:
      case RangeKind::SingleDecl:
      case RangeKind::MultiTypeMemberDecl:
      case RangeKind::Invalid:
         return false;
      case RangeKind::SingleExpression:
      case RangeKind::SingleStatement:
      case RangeKind::MultiStatement: {
         return checkExtractConditions(Info, Diag).
            success({CannotExtractReason::VoidType});
      }
   }
   llvm_unreachable("unhandled kind");
}

static StringRef correctNameInternal(AstContext &Ctx, StringRef Name,
                                     ArrayRef<ValueDecl*> AllVisibles) {
   // If we find the collision.
   bool FoundCollision = false;

   // The suffixes we cannot use by appending to the original given name.
   llvm::StringSet<> UsedSuffixes;
   for (auto VD : AllVisibles) {
      StringRef S = VD->getBaseName().userFacingName();
      if (!S.startswith(Name))
         continue;
      StringRef Suffix = S.substr(Name.size());
      if (Suffix.empty())
         FoundCollision = true;
      else
         UsedSuffixes.insert(Suffix);
   }
   if (!FoundCollision)
      return Name;

   // Find the first suffix we can use.
   std::string SuffixToUse;
   for (unsigned I = 1; ; I ++) {
      SuffixToUse = std::to_string(I);
      if (UsedSuffixes.count(SuffixToUse) == 0)
         break;
   }
   return Ctx.getIdentifier((llvm::Twine(Name) + SuffixToUse).str()).str();
}

static StringRef correctNewDeclName(DeclContext *DC, StringRef Name) {

   // Collect all visible decls in the decl context.
   llvm::SmallVector<ValueDecl*, 16> AllVisibles;
   VectorDeclConsumer Consumer(AllVisibles);
   AstContext &Ctx = DC->getAstContext();
   lookupVisibleDecls(Consumer, DC, true);
   return correctNameInternal(Ctx, Name, AllVisibles);
}

static Type sanitizeType(Type Ty) {
   // Transform lvalue type to inout type so that we can print it properly.
   return Ty.transform([](Type Ty) {
      if (Ty->is<LValueType>()) {
         return Type(InOutType::get(Ty->getRValueType()->getCanonicalType()));
      }
      return Ty;
   });
}

static SourceLoc
getNewFuncInsertLoc(DeclContext *DC, DeclContext*& InsertToContext) {
   if (auto D = DC->getInnermostDeclarationDeclContext()) {

      // If extracting from a getter/setter, we should skip both the immediate
      // getter/setter function and the individual var decl. The pattern binding
      // decl is the position before which we should insert the newly extracted
      // function.
      if (auto *FD = dyn_cast<AccessorDecl>(D)) {
         ValueDecl *SD = FD->getStorage();
         switch (SD->getKind()) {
            case DeclKind::Var:
               if (auto *PBD = cast<VarDecl>(SD)->getParentPatternBinding())
                  D = PBD;
               break;
            case DeclKind::Subscript:
               D = SD;
               break;
            default:
               break;
         }
      }

      auto Result = D->getStartLoc();
      assert(Result.isValid());

      // The insert loc should be before every decl attributes.
      for (auto Attr : D->getAttrs()) {
         auto Loc = Attr->getRangeWithAt().start;
         if (Loc.isValid() &&
             Loc.getOpaquePointerValue() < Result.getOpaquePointerValue())
            Result = Loc;
      }

      // The insert loc should be before the doc comments associated with this decl.
      if (!D->getRawComment().Comments.empty()) {
         auto Loc = D->getRawComment().Comments.front().Range.getStart();
         if (Loc.isValid() &&
             Loc.getOpaquePointerValue() < Result.getOpaquePointerValue()) {
            Result = Loc;
         }
      }
      InsertToContext = D->getDeclContext();
      return Result;
   }
   return SourceLoc();
}

static std::vector<NoteRegion>
getNotableRegions(StringRef SourceText, unsigned NameOffset, StringRef Name,
                  bool IsFunctionLike = false, bool IsNonInterfaceType = false) {
   auto InputBuffer = llvm::MemoryBuffer::getMemBufferCopy(SourceText,"<extract>");

   CompilerInvocation Invocation{};

   Invocation.getFrontendOptions().InputsAndOutputs.addInput(
      InputFile("<extract>", true, InputBuffer.get()));
   Invocation.getFrontendOptions().ModuleName = "extract";

   auto Instance = std::make_unique<polar::CompilerInstance>();
   if (Instance->setup(Invocation))
      llvm_unreachable("Failed setup");

   Instance->performParseOnly();

   unsigned BufferId = Instance->getPrimarySourceFile()->getBufferID().getValue();
   SourceManager &SM = Instance->getSourceMgr();
   SourceLoc NameLoc = SM.getLocForOffset(BufferId, NameOffset);
   auto LineAndCol = SM.getLineAndColumn(NameLoc);

   UnresolvedLoc UnresoledName{NameLoc, true};

   NameMatcher Matcher(*Instance->getPrimarySourceFile());
   auto Resolved = Matcher.resolve(llvm::makeArrayRef(UnresoledName), None);
   assert(!Resolved.empty() && "Failed to resolve generated func name loc");

   RenameLoc RenameConfig = {
      LineAndCol.first, LineAndCol.second,
      NameUsage::Definition, /*OldName=*/Name, /*NewName=*/"",
      IsFunctionLike, IsNonInterfaceType
   };
   RenameRangeDetailCollector Renamer(SM, Name);
   Renamer.addSyntacticRenameRanges(Resolved.back(), RenameConfig);
   auto Ranges = Renamer.Ranges;

   std::vector<NoteRegion> NoteRegions(Renamer.Ranges.size());
   std::transform(Ranges.begin(), Ranges.end(), NoteRegions.begin(),
                  [&SM](RenameRangeDetail &Detail) -> NoteRegion {
                     auto Start = SM.getLineAndColumn(Detail.Range.getStart());
                     auto End = SM.getLineAndColumn(Detail.Range.getEnd());
                     return {Detail.RangeKind, Start.first, Start.second, End.first, End.second, Detail.Index};
                  });

   return NoteRegions;
}

bool RefactoringActionExtractFunction::performChange() {
   // Check if the new name is ok.
   if (!Lexer::isIdentifier(PreferredName)) {
      DiagEngine.diagnose(SourceLoc(), diag::invalid_name, PreferredName);
      return true;
   }
   DeclContext *DC = RangeInfo.RangeContext;
   DeclContext *InsertToDC = nullptr;
   SourceLoc InsertLoc = getNewFuncInsertLoc(DC, InsertToDC);

   // Complain about no inserting position.
   if (InsertLoc.isInvalid()) {
      DiagEngine.diagnose(SourceLoc(), diag::no_insert_position);
      return true;
   }

   // Correct the given name if collision happens.
   PreferredName = correctNewDeclName(InsertToDC, PreferredName);

   // Collect the paramters to pass down to the new function.
   std::vector<ReferencedDecl> Parameters;
   for (auto &RD: RangeInfo.ReferencedDecls) {
      // If the referenced decl is declared elsewhere, no need to pass as parameter
      if (RD.VD->getDeclContext() != DC)
         continue;

      // We don't need to pass down implicitly declared variables, e.g. error in
      // a catch block.
      if (RD.VD->isImplicit()) {
         SourceLoc Loc = RD.VD->getStartLoc();
         if (Loc.isValid() &&
             SM.isBeforeInBuffer(RangeInfo.ContentRange.getStart(), Loc) &&
             SM.isBeforeInBuffer(Loc, RangeInfo.ContentRange.getEnd()))
            continue;
      }

      // If the referenced decl is declared inside the range, no need to pass
      // as parameter.
      if (RangeInfo.DeclaredDecls.end() !=
          std::find_if(RangeInfo.DeclaredDecls.begin(), RangeInfo.DeclaredDecls.end(),
                       [RD](DeclaredDecl DD) { return RD.VD == DD.VD; }))
         continue;

      // We don't need to pass down self.
      if (auto PD = dyn_cast<ParamDecl>(RD.VD)) {
         if (PD->isSelfParameter()) {
            continue;
         }
      }

      Parameters.emplace_back(RD.VD, sanitizeType(RD.Ty));
   }
   SmallString<64> Buffer;
   unsigned FuncBegin = Buffer.size();
   unsigned FuncNameOffset;
   {
      llvm::raw_svector_ostream OS(Buffer);

      if (!InsertToDC->isLocalContext()) {
         // Default to be file private.
         OS << tok::kw_fileprivate << " ";
      }

      // Inherit static if the containing function is.
      if (DC->getContextKind() == DeclContextKind::AbstractFunctionDecl) {
         if (auto FD = dyn_cast<FuncDecl>(static_cast<AbstractFunctionDecl*>(DC))) {
            if (FD->isStatic()) {
               OS << tok::kw_static << " ";
            }
         }
      }

      OS << tok::kw_func << " ";
      FuncNameOffset = Buffer.size() - FuncBegin;
      OS << PreferredName;
      OS << "(";
      for (auto &RD : Parameters) {
         OS << "_ " << RD.VD->getBaseName().userFacingName() << ": ";
         RD.Ty->reconstituteSugar(/*Recursive*/true)->print(OS);
         if (&RD != &Parameters.back())
            OS << ", ";
      }
      OS << ")";

      if (RangeInfo.ThrowingUnhandledError)
         OS << " " << tok::kw_throws;

      bool InsertedReturnType = false;
      if (auto Ty = RangeInfo.getType()) {
         // If the type of the range is not void, specify the return type.
         if (!Ty->isVoid()) {
            OS << " " << tok::arrow << " ";
            sanitizeType(Ty)->reconstituteSugar(/*Recursive*/true)->print(OS);
            InsertedReturnType = true;
         }
      }

      OS << " {\n";

      // Add "return" if the extracted entity is an expression.
      if (RangeInfo.Kind == RangeKind::SingleExpression && InsertedReturnType)
         OS << tok::kw_return << " ";
      OS << RangeInfo.ContentRange.str() << "\n}\n\n";
   }
   unsigned FuncEnd = Buffer.size();

   unsigned ReplaceBegin = Buffer.size();
   unsigned CallNameOffset;
   {
      llvm::raw_svector_ostream OS(Buffer);
      if (RangeInfo.exit() == ExitState::Positive)
         OS << tok::kw_return <<" ";
      CallNameOffset = Buffer.size() - ReplaceBegin;
      OS << PreferredName << "(";
      for (auto &RD : Parameters) {

         // Inout argument needs "&".
         if (RD.Ty->is<InOutType>())
            OS << "&";
         OS << RD.VD->getBaseName().userFacingName();
         if (&RD != &Parameters.back())
            OS << ", ";
      }
      OS << ")";
   }
   unsigned ReplaceEnd = Buffer.size();

   std::string ExtractedFuncName = PreferredName.str() + "(";
   for (size_t i = 0; i < Parameters.size(); ++i) {
      ExtractedFuncName += "_:";
   }
   ExtractedFuncName += ")";

   StringRef DeclStr(Buffer.begin() + FuncBegin, FuncEnd - FuncBegin);
   auto NotableFuncRegions = getNotableRegions(DeclStr, FuncNameOffset,
                                               ExtractedFuncName,
      /*IsFunctionLike=*/true);

   StringRef CallStr(Buffer.begin() + ReplaceBegin, ReplaceEnd - ReplaceBegin);
   auto NotableCallRegions = getNotableRegions(CallStr, CallNameOffset,
                                               ExtractedFuncName,
      /*IsFunctionLike=*/true);

   // Insert the new function's declaration.
   EditConsumer.accept(SM, InsertLoc, DeclStr, NotableFuncRegions);

   // Replace the code to extract with the function call.
   EditConsumer.accept(SM, RangeInfo.ContentRange, CallStr, NotableCallRegions);

   return false;
}

class RefactoringActionExtractExprBase {
   SourceFile *TheFile;
   ResolvedRangeInfo RangeInfo;
   DiagnosticEngine &DiagEngine;
   const bool ExtractRepeated;
   StringRef PreferredName;
   SourceEditConsumer &EditConsumer;

   AstContext &Ctx;
   SourceManager &SM;

public:
   RefactoringActionExtractExprBase(SourceFile *TheFile,
                                    ResolvedRangeInfo RangeInfo,
                                    DiagnosticEngine &DiagEngine,
                                    bool ExtractRepeated,
                                    StringRef PreferredName,
                                    SourceEditConsumer &EditConsumer) :
      TheFile(TheFile), RangeInfo(RangeInfo), DiagEngine(DiagEngine),
      ExtractRepeated(ExtractRepeated), PreferredName(PreferredName),
      EditConsumer(EditConsumer), Ctx(TheFile->getAstContext()),
      SM(Ctx.SourceMgr){}
   bool performChange();
};

/// This is to ensure all decl references in two expressions are identical.
struct ReferenceCollector: public SourceEntityWalker {
   llvm::SmallVector<ValueDecl*, 4> References;

   ReferenceCollector(Expr *E) { walk(E); }
   bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
                           TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef,
                           Type T, ReferenceMetaData Data) override {
      References.emplace_back(D);
      return true;
   }
   bool operator==(const ReferenceCollector &Other) const {
      if (References.size() != Other.References.size())
         return false;
      return std::equal(References.begin(), References.end(),
                        Other.References.begin());
   }
};

struct SimilarExprCollector: public SourceEntityWalker {
   SourceManager &SM;

   /// The expression under selection.
   Expr *SelectedExpr;
   llvm::ArrayRef<Token> AllTokens;
   llvm::SetVector<Expr*> &Bucket;

   /// The tokens included in the expression under selection.
   llvm::ArrayRef<Token> SelectedTokens;

   /// The referenced decls in the expression under selection.
   ReferenceCollector SelectedReferences;

   bool compareTokenContent(ArrayRef<Token> Left, ArrayRef<Token> Right) {
      if (Left.size() != Right.size())
         return false;
      return std::equal(Left.begin(), Left.end(), Right.begin(),
                        [](const Token &L, const Token& R) {
                           return L.getText() == R.getText();
                        });
   }

   /// Find all tokens included by an expression.
   llvm::ArrayRef<Token> getExprSlice(Expr *E) {
      return slice_token_array(AllTokens, E->getStartLoc(), E->getEndLoc());
   }

   SimilarExprCollector(SourceManager &SM, Expr* SelectedExpr,
                        llvm::ArrayRef<Token> AllTokens,
                        llvm::SetVector<Expr*> &Bucket): SM(SM), SelectedExpr(SelectedExpr),
                                                         AllTokens(AllTokens), Bucket(Bucket),
                                                         SelectedTokens(getExprSlice(SelectedExpr)),
                                                         SelectedReferences(SelectedExpr){}

   bool walkToExprPre(Expr *E) override {
      // We don't extract implicit expressions.
      if (E->isImplicit())
         return true;
      if (E->getKind() != SelectedExpr->getKind())
         return true;

      // First check the underlying token arrays have the same content.
      if (compareTokenContent(getExprSlice(E), SelectedTokens)) {
         ReferenceCollector CurrentReferences(E);

         // Next, check the referenced decls are same.
         if (CurrentReferences == SelectedReferences)
            Bucket.insert(E);
      }
      return true;
   }
};

bool RefactoringActionExtractExprBase::performChange() {
   // Check if the new name is ok.
   if (!Lexer::isIdentifier(PreferredName)) {
      DiagEngine.diagnose(SourceLoc(), diag::invalid_name, PreferredName);
      return true;
   }

   // Find the enclosing brace statement;
   ContextFinder Finder(*TheFile, RangeInfo.ContainedNodes.front(),
                        [](AstNode N) { return N.isStmt(StmtKind::Brace); });

   auto *SelectedExpr = RangeInfo.ContainedNodes[0].get<Expr*>();
   Finder.resolve();
   SourceLoc InsertLoc;
   llvm::SetVector<ValueDecl*> AllVisibleDecls;
   struct DeclCollector: public SourceEntityWalker {
      llvm::SetVector<ValueDecl*> &Bucket;
      DeclCollector(llvm::SetVector<ValueDecl*> &Bucket): Bucket(Bucket) {}
      bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
         if (auto *VD = dyn_cast<ValueDecl>(D))
            Bucket.insert(VD);
         return true;
      }
   } Collector(AllVisibleDecls);

   llvm::SetVector<Expr*> AllExpressions;

   if (!Finder.getContexts().empty()) {

      // Get the innermost brace statement.
      auto BS = static_cast<BraceStmt*>(Finder.getContexts().back().get<Stmt*>());

      // Collect all value decls inside the brace statement.
      Collector.walk(BS);

      if (ExtractRepeated) {
         // Collect all expressions we are going to extract.
         SimilarExprCollector(SM, SelectedExpr,
                              slice_token_array(TheFile->getAllTokens(),
                                                BS->getStartLoc(),
                                                BS->getEndLoc()),
                              AllExpressions).walk(BS);
      } else {
         AllExpressions.insert(SelectedExpr);
      }

      assert(!AllExpressions.empty() && "at least one expression is extracted.");
      for (auto Ele : BS->getElements()) {
         // Find the element that encloses the first expression under extraction.
         if (SM.rangeContains(Ele.getSourceRange(),
                              (*AllExpressions.begin())->getSourceRange())) {

            // Insert before the enclosing element.
            InsertLoc = Ele.getStartLoc();
         }
      }
   }

   // Complain about no inserting position.
   if (InsertLoc.isInvalid()) {
      DiagEngine.diagnose(SourceLoc(), diag::no_insert_position);
      return true;
   }

   // Correct name if collision happens.
   PreferredName = correctNameInternal(TheFile->getAstContext(), PreferredName,
                                       AllVisibleDecls.getArrayRef());

   // Print the type name of this expression.
   llvm::SmallString<16> TyBuffer;

   // We are not sure about the type of repeated expressions.
   if (!ExtractRepeated) {
      if (auto Ty = RangeInfo.getType()) {
         llvm::raw_svector_ostream OS(TyBuffer);
         OS << ": ";
         Ty->getRValueType()->reconstituteSugar(true)->print(OS);
      }
   }

   llvm::SmallString<64> DeclBuffer;
   llvm::raw_svector_ostream OS(DeclBuffer);
   unsigned StartOffset, EndOffset;
   OS << tok::kw_let << " ";
   StartOffset = DeclBuffer.size();
   OS << PreferredName;
   EndOffset = DeclBuffer.size();
   OS << TyBuffer.str() <<  " = " << RangeInfo.ContentRange.str() << "\n";

   NoteRegion DeclNameRegion{
      RefactoringRangeKind::BaseName,
      /*StartLine=*/1, /*StartColumn=*/StartOffset + 1,
      /*EndLine=*/1, /*EndColumn=*/EndOffset + 1,
      /*ArgIndex*/None
   };

   // Perform code change.
   EditConsumer.accept(SM, InsertLoc, DeclBuffer.str(), {DeclNameRegion});

   // Replace all occurrences of the extracted expression.
   for (auto *E : AllExpressions) {
      EditConsumer.accept(SM,
                          Lexer::getCharSourceRangeFromSourceRange(SM, E->getSourceRange()),
                          PreferredName,
                          {{
                              RefactoringRangeKind::BaseName,
                              /*StartLine=*/1, /*StartColumn-*/1, /*EndLine=*/1,
                              /*EndColumn=*/static_cast<unsigned int>(PreferredName.size() + 1),
                              /*ArgIndex*/None
                           }});
   }
   return false;
}

bool RefactoringActionExtractExpr::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   switch (Info.Kind) {
      case RangeKind::SingleExpression:
         // We disallow extract literal expression for two reasons:
         // (1) since we print the type for extracted expression, the type of a
         // literal may print as "int2048" where it is not typically users' choice;
         // (2) Extracting one literal provides little value for users.
         return checkExtractConditions(Info, Diag).success();
      case RangeKind::PartOfExpression:
      case RangeKind::SingleDecl:
      case RangeKind::MultiTypeMemberDecl:
      case RangeKind::SingleStatement:
      case RangeKind::MultiStatement:
      case RangeKind::Invalid:
         return false;
   }
   llvm_unreachable("unhandled kind");
}

bool RefactoringActionExtractExpr::performChange() {
   return RefactoringActionExtractExprBase(TheFile, RangeInfo,
                                           DiagEngine, false, PreferredName,
                                           EditConsumer).performChange();
}

bool RefactoringActionExtractRepeatedExpr::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   switch (Info.Kind) {
      case RangeKind::SingleExpression:
         return checkExtractConditions(Info, Diag).
            success({CannotExtractReason::Literal});
      case RangeKind::PartOfExpression:
      case RangeKind::SingleDecl:
      case RangeKind::MultiTypeMemberDecl:
      case RangeKind::SingleStatement:
      case RangeKind::MultiStatement:
      case RangeKind::Invalid:
         return false;
   }
   llvm_unreachable("unhandled kind");
}
bool RefactoringActionExtractRepeatedExpr::performChange() {
   return RefactoringActionExtractExprBase(TheFile, RangeInfo,
                                           DiagEngine, true, PreferredName,
                                           EditConsumer).performChange();
}


bool RefactoringActionMoveMembersToExtension::isApplicable(
   ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   switch (Info.Kind) {
      case RangeKind::SingleDecl:
      case RangeKind::MultiTypeMemberDecl: {
         DeclContext *DC = Info.RangeContext;

         // The the common decl context is not a nomial type, we cannot create an
         // extension for it
         if (!DC || !DC->getInnermostDeclarationDeclContext() ||
             !isa<NominalTypeDecl>(DC->getInnermostDeclarationDeclContext()))
            return false;


         // Members of types not declared at top file level cannot be extracted
         // to an extension at top file level
         if (DC->getParent()->getContextKind() != DeclContextKind::FileUnit)
            return false;

         // Check if contained nodes are all allowed decls.
         for (auto Node : Info.ContainedNodes) {
            Decl *D = Node.dyn_cast<Decl*>();
            if (!D)
               return false;

            if (isa<AccessorDecl>(D) || isa<DestructorDecl>(D) ||
                isa<EnumCaseDecl>(D) || isa<EnumElementDecl>(D))
               return false;
         }

         // We should not move instance variables with storage into the extension
         // because they are not allowed to be declared there
         for (auto DD : Info.DeclaredDecls) {
            if (auto ASD = dyn_cast<AbstractStorageDecl>(DD.VD)) {
               // Only disallow storages in the common decl context, allow them in
               // any subtypes
               if (ASD->hasStorage() && ASD->getDeclContext() == DC) {
                  return false;
               }
            }
         }

         return true;
      }
      case RangeKind::SingleExpression:
      case RangeKind::PartOfExpression:
      case RangeKind::SingleStatement:
      case RangeKind::MultiStatement:
      case RangeKind::Invalid:
         return false;
   }
   llvm_unreachable("unhandled kind");
}

bool RefactoringActionMoveMembersToExtension::performChange() {
   DeclContext *DC = RangeInfo.RangeContext;

   auto CommonTypeDecl =
      dyn_cast<NominalTypeDecl>(DC->getInnermostDeclarationDeclContext());
   assert(CommonTypeDecl && "Not applicable if common parent is no nomial type");

   SmallString<64> Buffer;
   llvm::raw_svector_ostream OS(Buffer);
   OS << "\n\n";
   OS << "extension " << CommonTypeDecl->getName() << " {\n";
   OS << RangeInfo.ContentRange.str().trim();
   OS << "\n}";

   // Insert extension after the type declaration
   EditConsumer.insertAfter(SM, CommonTypeDecl->getEndLoc(), Buffer);
   EditConsumer.remove(SM, RangeInfo.ContentRange);

   return false;
}

namespace {
// A SingleDecl range may not include all decls actually declared in that range:
// a var decl has accessors that aren't included. This will find those missing
// decls.
class FindAllSubDecls : public SourceEntityWalker {
   llvm::SmallPtrSetImpl<Decl *> &Found;
public:
   FindAllSubDecls(llvm::SmallPtrSetImpl<Decl *> &found)
      : Found(found) {}

   bool walkToDeclPre(Decl *D, CharSourceRange range) {
      // Record this Decl, and skip its contents if we've already touched it.
      if (!Found.insert(D).second)
         return false;

      if (auto ASD = dyn_cast<AbstractStorageDecl>(D)) {
         ASD->visitParsedAccessors([&](AccessorDecl *accessor) {
            Found.insert(accessor);
         });
      }
      return true;
   }
};
}
bool RefactoringActionReplaceBodiesWithFatalError::isApplicable(
   ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   switch (Info.Kind) {
      case RangeKind::SingleDecl:
      case RangeKind::MultiTypeMemberDecl: {
         llvm::SmallPtrSet<Decl *, 16> Found;
         for (auto decl : Info.DeclaredDecls) {
            FindAllSubDecls(Found).walk(decl.VD);
         }
         for (auto decl : Found) {
            auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
            if (AFD && !AFD->isImplicit())
               return true;
         }

         return false;
      }
      case RangeKind::SingleExpression:
      case RangeKind::PartOfExpression:
      case RangeKind::SingleStatement:
      case RangeKind::MultiStatement:
      case RangeKind::Invalid:
         return false;
   }
   llvm_unreachable("unhandled kind");
}

bool RefactoringActionReplaceBodiesWithFatalError::performChange() {
   const StringRef replacement = "{\nfatalError()\n}";
   llvm::SmallPtrSet<Decl *, 16> Found;
   for (auto decl : RangeInfo.DeclaredDecls) {
      FindAllSubDecls(Found).walk(decl.VD);
   }
   for (auto decl : Found) {
      auto AFD = dyn_cast<AbstractFunctionDecl>(decl);
      if (!AFD || AFD->isImplicit())
         continue;

      auto range = AFD->getBodySourceRange();
      // If we're in replacement mode (i.e. have an edit consumer), we can
      // rewrite the function body.
      auto charRange = Lexer::getCharSourceRangeFromSourceRange(SM, range);
      EditConsumer.accept(SM, charRange, replacement);

   }
   return false;
}

static std::pair<IfStmt *, IfStmt *>
findCollapseNestedIfTarget(ResolvedCursorInfo CursorInfo) {
   if (CursorInfo.Kind != CursorInfoKind::StmtStart)
      return {};

   // Ensure the statement is 'if' statement. It must not have 'else' clause.
   IfStmt *OuterIf = dyn_cast<IfStmt>(CursorInfo.TrailingStmt);
   if (!OuterIf)
      return {};
   if (OuterIf->getElseStmt())
      return {};

   // The body must contain a sole inner 'if' statement.
   auto Body = dyn_cast_or_null<BraceStmt>(OuterIf->getThenStmt());
   if (!Body || Body->getNumElements() != 1)
      return {};

   IfStmt *InnerIf =
      dyn_cast_or_null<IfStmt>(Body->getFirstElement().dyn_cast<Stmt *>());
   if (!InnerIf)
      return {};

   // Inner 'if' statement also cannot have 'else' clause.
   if (InnerIf->getElseStmt())
      return {};

   return {OuterIf, InnerIf};
}

bool RefactoringActionCollapseNestedIfStmt::
isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &Diag) {
   return findCollapseNestedIfTarget(CursorInfo).first;
}

bool RefactoringActionCollapseNestedIfStmt::performChange() {
   auto Target = findCollapseNestedIfTarget(CursorInfo);
   if (!Target.first)
      return true;
   auto OuterIf = Target.first;
   auto InnerIf = Target.second;

   EditorConsumerInsertStream OS(
      EditConsumer, SM,
      Lexer::getCharSourceRangeFromSourceRange(SM, OuterIf->getSourceRange()));

   OS << tok::kw_if << " ";

   // Emit conditions.
   bool first = true;
   for (auto &C : llvm::concat<StmtConditionElement>(OuterIf->getCond(),
                                                     InnerIf->getCond())) {
      if (first)
         first = false;
      else
         OS << ", ";
      OS << Lexer::getCharSourceRangeFromSourceRange(SM, C.getSourceRange())
         .str();
   }

   // Emit body.
   OS << " ";
   OS << Lexer::getCharSourceRangeFromSourceRange(
      SM, InnerIf->getThenStmt()->getSourceRange())
      .str();
   return false;
}

static std::unique_ptr<llvm::SetVector<Expr*>>
findConcatenatedExpressions(ResolvedRangeInfo Info, AstContext &Ctx) {
   Expr *E = nullptr;

   switch (Info.Kind) {
      case RangeKind::SingleExpression:
         // FIXME: the range info kind should imply non-empty list.
         if (!Info.ContainedNodes.empty())
            E = Info.ContainedNodes[0].get<Expr*>();
         else
            return nullptr;
         break;
      case RangeKind::PartOfExpression:
         E = Info.CommonExprParent;
         break;
      default:
         return nullptr;
   }

   assert(E);

   struct StringInterpolationExprFinder: public SourceEntityWalker {
      std::unique_ptr<llvm::SetVector<Expr*>> Bucket = std::make_unique<llvm::SetVector<Expr*>>();
      AstContext &Ctx;

      bool IsValidInterpolation = true;
      StringInterpolationExprFinder(AstContext &Ctx): Ctx(Ctx) {}

      bool isConcatenationExpr(DeclRefExpr* Expr) {
         if (!Expr)
            return false;
         auto *FD = dyn_cast<FuncDecl>(Expr->getDecl());
         if (FD == nullptr || (FD != Ctx.getPlusFunctionOnString() &&
                               FD != Ctx.getPlusFunctionOnRangeReplaceableCollection())) {
            return false;
         }
         return true;
      }

      bool walkToExprPre(Expr *E) {
         if (E->isImplicit())
            return true;
         // FIXME: we should have ErrorType instead of null.
         if (E->getType().isNull())
            return true;
         auto ExprType = E->getType()->getNominalOrBoundGenericNominal();
         //Only binary concatenation operators should exist in expression
         if (E->getKind() == ExprKind::Binary) {
            auto *BE = dyn_cast<BinaryExpr>(E);
            auto *OperatorDeclRef = BE->getSemanticFn()->getMemberOperatorRef();
            if (!(isConcatenationExpr(OperatorDeclRef)
                  && ExprType == Ctx.getStringDecl())) {
               IsValidInterpolation = false;
               return false;
            }
            return true;
         }
         // Everything that evaluates to string should be gathered.
         if (ExprType == Ctx.getStringDecl()) {
            Bucket->insert(E);
            return false;
         }
         if (auto *DR = dyn_cast<DeclRefExpr>(E)) {
            // Checks whether all function references in expression are concatenations.
            auto *FD = dyn_cast<FuncDecl>(DR->getDecl());
            auto IsConcatenation = isConcatenationExpr(DR);
            if (FD && IsConcatenation) {
               return false;
            }
         }
         // There was non-expected expression, it's not valid interpolation then.
         IsValidInterpolation = false;
         return false;
      }
   } Walker(Ctx);
   Walker.walk(E);

   // There should be two or more expressions to convert.
   if (!Walker.IsValidInterpolation || Walker.Bucket->size() < 2)
      return nullptr;

   return std::move(Walker.Bucket);
}

static void interpolatedExpressionForm(Expr *E, SourceManager &SM,
                                       llvm::raw_ostream &OS) {
   if (auto *Literal = dyn_cast<StringLiteralExpr>(E)) {
      OS << Literal->getValue();
      return;
   }
   auto ExpStr = Lexer::getCharSourceRangeFromSourceRange(SM,
                                                          E->getSourceRange()).str().str();
   if (isa<InterpolatedStringLiteralExpr>(E)) {
      ExpStr.erase(0, 1);
      ExpStr.pop_back();
      OS << ExpStr;
      return;
   }
   OS << "\\(" << ExpStr << ")";
}

bool RefactoringActionConvertStringsConcatenationToInterpolation::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   auto RangeContext = Info.RangeContext;
   if (RangeContext) {
      auto &Ctx = Info.RangeContext->getAstContext();
      return findConcatenatedExpressions(Info, Ctx) != nullptr;
   }
   return false;
}

bool RefactoringActionConvertStringsConcatenationToInterpolation::performChange() {
   auto Expressions = findConcatenatedExpressions(RangeInfo, Ctx);
   if (!Expressions)
      return true;
   EditorConsumerInsertStream OS(EditConsumer, SM, RangeInfo.ContentRange);
   OS << "\"";
   for (auto It = Expressions->begin(); It != Expressions->end(); It++) {
      interpolatedExpressionForm(*It, SM, OS);
   }
   OS << "\"";
   return false;
}

/// Abstract helper class containing info about an IfExpr
/// that can be expanded into an IfStmt.
class ExpandableTernaryExprInfo {

public:
   virtual ~ExpandableTernaryExprInfo() {}

   virtual IfExpr *getIf() = 0;

   virtual SourceRange getNameRange() = 0;

   virtual Type getType() = 0;

   virtual bool shouldDeclareNameAndType() {
      return !getType().isNull();
   }

   virtual bool isValid() {

      //Ensure all public properties are non-nil and valid
      if (!getIf() || !getNameRange().isValid())
         return false;
      if (shouldDeclareNameAndType() && getType().isNull())
         return false;

      return true; //valid
   }

   CharSourceRange getNameCharRange(const SourceManager &SM) {
      return Lexer::getCharSourceRangeFromSourceRange(SM, getNameRange());
   }
};

/// Concrete subclass containing info about an AssignExpr
/// where the source is the expandable IfExpr.
class ExpandableAssignTernaryExprInfo: public ExpandableTernaryExprInfo {

public:
   ExpandableAssignTernaryExprInfo(AssignExpr *Assign): Assign(Assign) {}

   IfExpr *getIf() {
      if (!Assign)
         return nullptr;
      return dyn_cast_or_null<IfExpr>(Assign->getSrc());
   }

   SourceRange getNameRange() {
      auto Invalid = SourceRange();

      if (!Assign)
         return Invalid;

      if (auto dest = Assign->getDest())
         return dest->getSourceRange();

      return Invalid;
   }

   Type getType() {
      return nullptr;
   }

private:
   AssignExpr *Assign = nullptr;
};

/// Concrete subclass containing info about a PatternBindingDecl
/// where the pattern initializer is the expandable IfExpr.
class ExpandableBindingTernaryExprInfo: public ExpandableTernaryExprInfo {

public:
   ExpandableBindingTernaryExprInfo(PatternBindingDecl *Binding):
      Binding(Binding) {}

   IfExpr *getIf() {
      if (Binding && Binding->getNumPatternEntries() == 1) {
         if (auto *Init = Binding->getInit(0)) {
            return dyn_cast<IfExpr>(Init);
         }
      }

      return nullptr;
   }

   SourceRange getNameRange() {
      if (auto Pattern = getNamePattern())
         return Pattern->getSourceRange();

      return SourceRange();
   }

   Type getType() {
      if (auto Pattern = getNamePattern())
         return Pattern->getType();

      return nullptr;
   }

private:
   Pattern *getNamePattern() {
      if (!Binding || Binding->getNumPatternEntries() != 1)
         return nullptr;

      auto Pattern = Binding->getPattern(0);

      if (!Pattern)
         return nullptr;

      if (auto TyPattern = dyn_cast<TypedPattern>(Pattern))
         Pattern = TyPattern->getSubPattern();

      return Pattern;
   }

   PatternBindingDecl *Binding = nullptr;
};

std::unique_ptr<ExpandableTernaryExprInfo>
findExpandableTernaryExpression(ResolvedRangeInfo Info) {

   if (Info.Kind != RangeKind::SingleDecl
       && Info.Kind != RangeKind:: SingleExpression)
      return nullptr;

   if (Info.ContainedNodes.size() != 1)
      return nullptr;

   if (auto D = Info.ContainedNodes[0].dyn_cast<Decl*>())
      if (auto Binding = dyn_cast<PatternBindingDecl>(D))
         return std::make_unique<ExpandableBindingTernaryExprInfo>(Binding);

   if (auto E = Info.ContainedNodes[0].dyn_cast<Expr*>())
      if (auto Assign = dyn_cast<AssignExpr>(E))
         return std::make_unique<ExpandableAssignTernaryExprInfo>(Assign);

   return nullptr;
}

bool RefactoringActionExpandTernaryExpr::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   auto Target = findExpandableTernaryExpression(Info);
   return Target && Target->isValid();
}

bool RefactoringActionExpandTernaryExpr::performChange() {
   auto Target = findExpandableTernaryExpression(RangeInfo);

   if (!Target || !Target->isValid())
      return true; //abort

   auto NameCharRange = Target->getNameCharRange(SM);

   auto IfRange = Target->getIf()->getSourceRange();
   auto IfCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, IfRange);

   auto CondRange = Target->getIf()->getCondExpr()->getSourceRange();
   auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, CondRange);

   auto ThenRange = Target->getIf()->getThenExpr()->getSourceRange();
   auto ThenCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ThenRange);

   auto ElseRange = Target->getIf()->getElseExpr()->getSourceRange();
   auto ElseCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ElseRange);

   llvm::SmallString<64> DeclBuffer;
   llvm::raw_svector_ostream OS(DeclBuffer);

   llvm::StringRef Space = " ";
   llvm::StringRef NewLine = "\n";

   if (Target->shouldDeclareNameAndType()) {
      //Specifier will not be replaced; append after specifier
      OS << NameCharRange.str() << tok::colon << Space;
      OS << Target->getType() << NewLine;
   }

   OS << tok::kw_if << Space;
   OS << CondCharRange.str() << Space;
   OS << tok::l_brace << NewLine;

   OS << NameCharRange.str() << Space;
   OS << tok::equal << Space;
   OS << ThenCharRange.str() << NewLine;

   OS << tok::r_brace << Space;
   OS << tok::kw_else << Space;
   OS << tok::l_brace << NewLine;

   OS << NameCharRange.str() << Space;
   OS << tok::equal << Space;
   OS << ElseCharRange.str() << NewLine;

   OS << tok::r_brace;

   //Start replacement with name range, skip the specifier
   auto ReplaceRange(NameCharRange);
   ReplaceRange.widen(IfCharRange);

   EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());

   return false; //don't abort
}

bool RefactoringActionConvertIfLetExprToGuardExpr::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {

   if (Info.Kind != RangeKind::SingleStatement
       && Info.Kind != RangeKind::MultiStatement)
      return false;

   if (Info.ContainedNodes.empty())
      return false;

   IfStmt *If = nullptr;

   if (Info.ContainedNodes.size() == 1) {
      if (auto S = Info.ContainedNodes[0].dyn_cast<Stmt*>()) {
         If = dyn_cast<IfStmt>(S);
      }
   }

   if (!If)
      return false;

   auto CondList = If->getCond();

   if (CondList.size() == 1) {
      auto E = CondList[0];
      auto P = E.getKind();
      if (P == polar::StmtConditionElement::CK_PatternBinding) {
         auto Body = dyn_cast_or_null<BraceStmt>(If->getThenStmt());
         if (Body)
            return true;
      }
   }

   return false;
}

bool RefactoringActionConvertIfLetExprToGuardExpr::performChange() {

   auto S = RangeInfo.ContainedNodes[0].dyn_cast<Stmt*>();
   IfStmt *If = dyn_cast<IfStmt>(S);
   auto CondList = If->getCond();

   // Get if-let condition
   SourceRange range = CondList[0].getSourceRange();
   SourceManager &SM = RangeInfo.RangeContext->getAstContext().SourceMgr;
   auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, range);

   auto Body = dyn_cast_or_null<BraceStmt>(If->getThenStmt());

   // Get if-let then body.
   auto firstElement = Body->getFirstElement();
   auto lastElement = Body->getLastElement();
   SourceRange bodyRange = firstElement.getSourceRange();
   bodyRange.widen(lastElement.getSourceRange());
   auto BodyCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, bodyRange);

   llvm::SmallString<64> DeclBuffer;
   llvm::raw_svector_ostream OS(DeclBuffer);

   llvm::StringRef Space = " ";
   llvm::StringRef NewLine = "\n";

   OS << tok::kw_guard << Space;
   OS << CondCharRange.str().str() << Space;
   OS << tok::kw_else << Space;
   OS << tok::l_brace << NewLine;

   // Get if-let else body.
   if (auto *ElseBody = dyn_cast_or_null<BraceStmt>(If->getElseStmt())) {
      auto firstElseElement = ElseBody->getFirstElement();
      auto lastElseElement = ElseBody->getLastElement();
      SourceRange elseBodyRange = firstElseElement.getSourceRange();
      elseBodyRange.widen(lastElseElement.getSourceRange());
      auto ElseBodyCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, elseBodyRange);
      OS << ElseBodyCharRange.str().str() << NewLine;
   }

   OS << tok::kw_return << NewLine;
   OS << tok::r_brace << NewLine;
   OS << BodyCharRange.str().str();

   // Replace if-let to guard
   auto ReplaceRange = RangeInfo.ContentRange;
   EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());

   return false;
}

bool RefactoringActionConvertGuardExprToIfLetExpr::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   if (Info.Kind != RangeKind::SingleStatement
       && Info.Kind != RangeKind::MultiStatement)
      return false;

   if (Info.ContainedNodes.empty())
      return false;

   GuardStmt *guardStmt = nullptr;

   if (Info.ContainedNodes.size() > 0) {
      if (auto S = Info.ContainedNodes[0].dyn_cast<Stmt*>()) {
         guardStmt = dyn_cast<GuardStmt>(S);
      }
   }

   if (!guardStmt)
      return false;

   auto CondList = guardStmt->getCond();

   if (CondList.size() == 1) {
      auto E = CondList[0];
      auto P = E.getPatternOrNull();
      if (P && E.getKind() == polar::StmtConditionElement::CK_PatternBinding)
         return true;
   }

   return false;
}

bool RefactoringActionConvertGuardExprToIfLetExpr::performChange() {

   // Get guard stmt
   auto S = RangeInfo.ContainedNodes[0].dyn_cast<Stmt*>();
   GuardStmt *Guard = dyn_cast<GuardStmt>(S);

   // Get guard condition
   auto CondList = Guard->getCond();

   // Get guard condition source
   SourceRange range = CondList[0].getSourceRange();
   SourceManager &SM = RangeInfo.RangeContext->getAstContext().SourceMgr;
   auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, range);

   llvm::SmallString<64> DeclBuffer;
   llvm::raw_svector_ostream OS(DeclBuffer);

   llvm::StringRef Space = " ";
   llvm::StringRef NewLine = "\n";

   OS << tok::kw_if << Space;
   OS << CondCharRange.str().str() << Space;
   OS << tok::l_brace << NewLine;

   // Get nodes after guard to place them at if-let body
   if (RangeInfo.ContainedNodes.size() > 1) {
      auto S = RangeInfo.ContainedNodes[1].getSourceRange();
      S.widen(RangeInfo.ContainedNodes.back().getSourceRange());
      auto BodyCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, S);
      OS << BodyCharRange.str().str() << NewLine;
   }
   OS << tok::r_brace;

   // Get guard body
   auto Body = dyn_cast_or_null<BraceStmt>(Guard->getBody());

   if (Body && Body->getNumElements() > 1) {
      auto firstElement = Body->getFirstElement();
      auto lastElement = Body->getLastElement();
      SourceRange bodyRange = firstElement.getSourceRange();
      bodyRange.widen(lastElement.getSourceRange());
      auto BodyCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, bodyRange);
      OS << Space << tok::kw_else << Space << tok::l_brace << NewLine;
      OS << BodyCharRange.str().str() << NewLine;
      OS << tok::r_brace;
   }

   // Replace guard to if-let
   auto ReplaceRange = RangeInfo.ContentRange;
   EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());

   return false;
}

/// Struct containing info about an IfStmt that can be converted into an IfExpr.
struct ConvertToTernaryExprInfo {
   ConvertToTernaryExprInfo() {}

   Expr *AssignDest() {

      if (!Then || !Then->getDest() || !Else || !Else->getDest())
         return nullptr;

      auto ThenDest = Then->getDest();
      auto ElseDest = Else->getDest();

      if (ThenDest->getKind() != ElseDest->getKind())
         return nullptr;

      switch (ThenDest->getKind()) {
         case ExprKind::DeclRef: {
            auto ThenRef = dyn_cast<DeclRefExpr>(Then->getDest());
            auto ElseRef = dyn_cast<DeclRefExpr>(Else->getDest());

            if (!ThenRef || !ThenRef->getDecl() || !ElseRef || !ElseRef->getDecl())
               return nullptr;

            auto ThenName = ThenRef->getDecl()->getFullName();
            auto ElseName = ElseRef->getDecl()->getFullName();

            if (ThenName.compare(ElseName) != 0)
               return nullptr;

            return Then->getDest();
         }
         case ExprKind::Tuple: {
            auto ThenTuple = dyn_cast<TupleExpr>(Then->getDest());
            auto ElseTuple = dyn_cast<TupleExpr>(Else->getDest());

            if (!ThenTuple || !ElseTuple)
               return nullptr;

            auto ThenNames = ThenTuple->getElementNames();
            auto ElseNames = ElseTuple->getElementNames();

            if (!ThenNames.equals(ElseNames))
               return nullptr;

            return ThenTuple;
         }
         default:
            return nullptr;
      }
   }

   Expr *ThenSrc() {
      if (!Then)
         return nullptr;
      return Then->getSrc();
   }

   Expr *ElseSrc() {
      if (!Else)
         return nullptr;
      return Else->getSrc();
   }

   bool isValid() {
      if (!Cond || !AssignDest() || !ThenSrc() || !ElseSrc()
          || !IfRange.isValid())
         return false;

      return true;
   }

   PatternBindingDecl *Binding = nullptr; //optional

   Expr *Cond = nullptr; //required
   AssignExpr *Then = nullptr; //required
   AssignExpr *Else = nullptr; //required
   SourceRange IfRange;
};

ConvertToTernaryExprInfo
findConvertToTernaryExpression(ResolvedRangeInfo Info) {

   auto notFound = ConvertToTernaryExprInfo();

   if (Info.Kind != RangeKind::SingleStatement
       && Info.Kind != RangeKind::MultiStatement)
      return notFound;

   if (Info.ContainedNodes.empty())
      return notFound;

   struct AssignExprFinder: public SourceEntityWalker {

      AssignExpr *Assign = nullptr;

      AssignExprFinder(Stmt* S) {
         if (S)
            walk(S);
      }

      virtual bool walkToExprPre(Expr *E) {
         Assign = dyn_cast<AssignExpr>(E);
         return false;
      }
   };

   ConvertToTernaryExprInfo Target;

   IfStmt *If = nullptr;

   if (Info.ContainedNodes.size() == 1) {
      if (auto S = Info.ContainedNodes[0].dyn_cast<Stmt*>())
         If = dyn_cast<IfStmt>(S);
   }

   if (Info.ContainedNodes.size() == 2) {
      if (auto D = Info.ContainedNodes[0].dyn_cast<Decl*>())
         Target.Binding = dyn_cast<PatternBindingDecl>(D);
      if (auto S = Info.ContainedNodes[1].dyn_cast<Stmt*>())
         If = dyn_cast<IfStmt>(S);
   }

   if (!If)
      return notFound;

   auto CondList = If->getCond();

   if (CondList.size() != 1)
      return notFound;

   Target.Cond = CondList[0].getBooleanOrNull();
   Target.IfRange = If->getSourceRange();

   Target.Then = AssignExprFinder(If->getThenStmt()).Assign;
   Target.Else = AssignExprFinder(If->getElseStmt()).Assign;

   return Target;
}

bool RefactoringActionConvertToTernaryExpr::
isApplicable(ResolvedRangeInfo Info, DiagnosticEngine &Diag) {
   return findConvertToTernaryExpression(Info).isValid();
}

bool RefactoringActionConvertToTernaryExpr::performChange() {
   auto Target = findConvertToTernaryExpression(RangeInfo);

   if (!Target.isValid())
      return true; //abort

   llvm::SmallString<64> DeclBuffer;
   llvm::raw_svector_ostream OS(DeclBuffer);

   llvm::StringRef Space = " ";

   auto IfRange = Target.IfRange;
   auto ReplaceRange = Lexer::getCharSourceRangeFromSourceRange(SM, IfRange);

   auto CondRange = Target.Cond->getSourceRange();
   auto CondCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, CondRange);

   auto ThenRange = Target.ThenSrc()->getSourceRange();
   auto ThenCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ThenRange);

   auto ElseRange = Target.ElseSrc()->getSourceRange();
   auto ElseCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, ElseRange);

   CharSourceRange DestCharRange;

   if (Target.Binding) {
      auto DestRange = Target.Binding->getSourceRange();
      DestCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, DestRange);
      ReplaceRange.widen(DestCharRange);
   } else {
      auto DestRange = Target.AssignDest()->getSourceRange();
      DestCharRange = Lexer::getCharSourceRangeFromSourceRange(SM, DestRange);
   }

   OS << DestCharRange.str() << Space << tok::equal << Space;
   OS << CondCharRange.str() << Space << tok::question_postfix << Space;
   OS << ThenCharRange.str() << Space << tok::colon << Space;
   OS << ElseCharRange.str();

   EditConsumer.accept(SM, ReplaceRange, DeclBuffer.str());

   return false; //don't abort
}

/// The helper class analyzes a given nominal decl or an extension decl to
/// decide whether stubs are required to filled in and the context in which
/// these stubs should be filled.
class FillInterfaceStubContext {

   std::vector<ValueDecl*> getUnsatisfiedRequirements(const DeclContext *DC);

   /// Context in which the content should be filled; this could be either a
   /// nominal type declaraion or an extension declaration.
   DeclContext *DC;

   /// The type that adopts the required protocol stubs. For nominal type decl, this
   /// should be the declared type itself; for extension decl, this should be the
   /// extended type at hand.
   Type Adopter;

   /// The start location of the decl, either nominal type or extension, for the
   /// printer to figure out the right indentation.
   SourceLoc StartLoc;

   /// The location of '{' for the decl, thus we know where to insert the filling
   /// stubs.
   SourceLoc BraceStartLoc;

   /// The value decls that should be satisfied; this could be either function
   /// decls, property decls, or required type alias.
   std::vector<ValueDecl*> FillingContents;

public:
   FillInterfaceStubContext(ExtensionDecl *ED) : DC(ED),
                                                 Adopter(ED->getExtendedType()), StartLoc(ED->getStartLoc()),
                                                 BraceStartLoc(ED->getBraces().start),
                                                 FillingContents(getUnsatisfiedRequirements(ED)) {};

   FillInterfaceStubContext(NominalTypeDecl *ND) : DC(ND),
                                                   Adopter(ND->getDeclaredType()), StartLoc(ND->getStartLoc()),
                                                   BraceStartLoc(ND->getBraces().start),
                                                   FillingContents(getUnsatisfiedRequirements(ND)) {};

   FillInterfaceStubContext() : DC(nullptr), Adopter(), FillingContents({}) {};

   static FillInterfaceStubContext getContextFromCursorInfo(ResolvedCursorInfo Tok);

   ArrayRef<ValueDecl*> getFillingContents() const {
      return llvm::makeArrayRef(FillingContents);
   }

   DeclContext *getFillingContext() const { return DC; }

   bool canProceed() const {
      return StartLoc.isValid() && BraceStartLoc.isValid() &&
             !getFillingContents().empty();
   }

   Type getAdopter() const { return Adopter; }
   SourceLoc getContextStartLoc() const { return StartLoc; }
   SourceLoc getBraceStartLoc() const { return BraceStartLoc; }
};

FillInterfaceStubContext FillInterfaceStubContext::
getContextFromCursorInfo(ResolvedCursorInfo CursorInfo) {
   if(!CursorInfo.isValid())
      return FillInterfaceStubContext();
   if (!CursorInfo.IsRef) {
      // If the type name is on the declared nominal, e.g. "class A {}"
      if (auto ND = dyn_cast<NominalTypeDecl>(CursorInfo.ValueD)) {
         return FillInterfaceStubContext(ND);
      }
   } else if (auto *ED = CursorInfo.ExtTyRef) {
      // If the type ref is on a declared extension, e.g. "extension A {}"
      return FillInterfaceStubContext(ED);
   }
   return FillInterfaceStubContext();
}

std::vector<ValueDecl*> FillInterfaceStubContext::
getUnsatisfiedRequirements(const DeclContext *DC) {
   // The results to return.
   std::vector<ValueDecl*> NonWitnessedReqs;

   // For each conformance of the extended nominal.
   for(InterfaceConformance *Con : DC->getLocalConformances()) {

      // Collect non-witnessed requirements.
      Con->forEachNonWitnessedRequirement(
         [&](ValueDecl *VD) { NonWitnessedReqs.push_back(VD); });
   }

   return NonWitnessedReqs;
}

bool RefactoringActionFillInterfaceStub::
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   return FillInterfaceStubContext::getContextFromCursorInfo(Tok).canProceed();
};

bool RefactoringActionFillInterfaceStub::performChange() {
   // Get the filling protocol context from the input token.
   FillInterfaceStubContext Context = FillInterfaceStubContext::
   getContextFromCursorInfo(CursorInfo);

   assert(Context.canProceed());
   assert(!Context.getFillingContents().empty());
   assert(Context.getFillingContext());
   llvm::SmallString<128> Text;
   {
      llvm::raw_svector_ostream SS(Text);
      Type Adopter = Context.getAdopter();
      SourceLoc Loc = Context.getContextStartLoc();
      auto Contents = Context.getFillingContents();

      // For each unsatisfied requirement, print the stub to the buffer.
      std::for_each(Contents.begin(), Contents.end(), [&](ValueDecl *VD) {
         printRequirementStub(VD, Context.getFillingContext(), Adopter, Loc, SS);
      });
   }

   // Insert all stubs after '{' in the extension/nominal type decl.
   EditConsumer.insertAfter(SM, Context.getBraceStartLoc(), Text);
   return false;
}

ArrayRef<RefactoringKind>
collectAvailableRefactoringsAtCursor(SourceFile *SF, unsigned Line,
                                     unsigned Column,
                                     std::vector<RefactoringKind> &Scratch,
                                     llvm::ArrayRef<DiagnosticConsumer*> DiagConsumers) {
   // Prepare the tool box.
   AstContext &Ctx = SF->getAstContext();
   SourceManager &SM = Ctx.SourceMgr;
   DiagnosticEngine DiagEngine(SM);
   std::for_each(DiagConsumers.begin(), DiagConsumers.end(),
                 [&](DiagnosticConsumer *Con) { DiagEngine.addConsumer(*Con); });
   SourceLoc Loc = SM.getLocForLineCol(SF->getBufferID().getValue(), Line, Column);
   if (Loc.isInvalid())
      return {};
   ResolvedCursorInfo Tok = evaluateOrDefault(SF->getAstContext().evaluator,
                                              CursorInfoRequest{CursorInfoOwner(SF, Lexer::getLocForStartOfToken(SM, Loc))},
                                              ResolvedCursorInfo());
   return collectAvailableRefactorings(SF, Tok, Scratch, /*Exclude rename*/false);
}

static EnumDecl* getEnumDeclFromSwitchStmt(SwitchStmt *SwitchS) {
   if (auto SubjectTy = SwitchS->getSubjectExpr()->getType()) {
      // FIXME: Support more complex subject like '(Enum1, Enum2)'.
      return dyn_cast_or_null<EnumDecl>(SubjectTy->getAnyNominal());
   }
   return nullptr;
}

static bool performCasesExpansionInSwitchStmt(SwitchStmt *SwitchS,
                                              DiagnosticEngine &DiagEngine,
                                              SourceLoc ExpandedStmtLoc,
                                              EditorConsumerInsertStream &OS
) {
   // Assume enum elements are not handled in the switch statement.
   auto EnumDecl = getEnumDeclFromSwitchStmt(SwitchS);
   assert(EnumDecl);
   llvm::DenseSet<EnumElementDecl*> UnhandledElements;
   EnumDecl->getAllElements(UnhandledElements);
   for (auto Current : SwitchS->getCases()) {
      if (Current->isDefault()) {
         continue;
      }
      // For each handled enum element, remove it from the bucket.
      for (auto Item : Current->getCaseLabelItems()) {
         if (auto *EEP = dyn_cast_or_null<EnumElementPattern>(Item.getPattern())) {
            UnhandledElements.erase(EEP->getElementDecl());
         }
      }
   }

   // If all enum elements are handled in the switch statement, issue error.
   if (UnhandledElements.empty()) {
      DiagEngine.diagnose(ExpandedStmtLoc, diag::no_remaining_cases);
      return true;
   }

   printEnumElementsAsCases(UnhandledElements, OS);
   return false;
}

// Finds SwitchStmt that contains given CaseStmt.
static SwitchStmt* findEnclosingSwitchStmt(CaseStmt *CS,
                                           SourceFile *SF,
                                           DiagnosticEngine &DiagEngine) {
   auto IsSwitch = [](AstNode Node) {
      return Node.is<Stmt*>() &&
             Node.get<Stmt*>()->getKind() == StmtKind::Switch;
   };
   ContextFinder Finder(*SF, CS, IsSwitch);
   Finder.resolve();

   // If failed to find the switch statement, issue error.
   if (Finder.getContexts().empty()) {
      DiagEngine.diagnose(CS->getStartLoc(), diag::no_parent_switch);
      return nullptr;
   }
   auto *SwitchS = static_cast<SwitchStmt*>(Finder.getContexts().back().
      get<Stmt*>());
   // Make sure that CaseStmt is included in switch that was found.
   auto Cases = SwitchS->getCases();
   auto Default = std::find(Cases.begin(), Cases.end(), CS);
   if (Default == Cases.end()) {
      DiagEngine.diagnose(CS->getStartLoc(), diag::no_parent_switch);
      return nullptr;
   }
   return SwitchS;
}

bool RefactoringActionExpandDefault::
isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &Diag) {
   auto Exit = [&](bool Applicable) {
      if (!Applicable)
         Diag.diagnose(SourceLoc(), diag::invalid_default_location);
      return Applicable;
   };
   if (CursorInfo.Kind != CursorInfoKind::StmtStart)
      return Exit(false);
   if (auto *CS = dyn_cast<CaseStmt>(CursorInfo.TrailingStmt)) {
      auto EnclosingSwitchStmt = findEnclosingSwitchStmt(CS,
                                                         CursorInfo.SF,
                                                         Diag);
      if (!EnclosingSwitchStmt)
         return false;
      auto EnumD = getEnumDeclFromSwitchStmt(EnclosingSwitchStmt);
      auto IsApplicable = CS->isDefault() && EnumD != nullptr;
      return IsApplicable;
   }
   return Exit(false);
}

bool RefactoringActionExpandDefault::performChange() {
   // If we've not seen the default statement inside the switch statement, issue
   // error.
   auto *CS = static_cast<CaseStmt*>(CursorInfo.TrailingStmt);
   auto *SwitchS = findEnclosingSwitchStmt(CS, TheFile, DiagEngine);
   assert(SwitchS);
   EditorConsumerInsertStream OS(EditConsumer, SM,
                                 Lexer::getCharSourceRangeFromSourceRange(SM,
                                                                          CS->getLabelItemsRange()));
   return performCasesExpansionInSwitchStmt(SwitchS,
                                            DiagEngine,
                                            CS->getStartLoc(),
                                            OS);
}

bool RefactoringActionExpandSwitchCases::
isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &DiagEngine) {
   if (!CursorInfo.TrailingStmt)
      return false;
   if (auto *Switch = dyn_cast<SwitchStmt>(CursorInfo.TrailingStmt)) {
      return getEnumDeclFromSwitchStmt(Switch);
   }
   return false;
}

bool RefactoringActionExpandSwitchCases::performChange() {
   auto *SwitchS = dyn_cast<SwitchStmt>(CursorInfo.TrailingStmt);
   assert(SwitchS);

   auto InsertRange = CharSourceRange();
   auto Cases = SwitchS->getCases();
   auto Default = std::find_if(Cases.begin(), Cases.end(), [](CaseStmt *Stmt) {
      return Stmt->isDefault();
   });
   if (Default != Cases.end()) {
      auto DefaultRange = (*Default)->getLabelItemsRange();
      InsertRange = Lexer::getCharSourceRangeFromSourceRange(SM, DefaultRange);
   } else {
      auto RBraceLoc = SwitchS->getRBraceLoc();
      InsertRange = CharSourceRange(SM, RBraceLoc, RBraceLoc);
   }
   EditorConsumerInsertStream OS(EditConsumer, SM, InsertRange);
   if (SM.getLineNumber(SwitchS->getLBraceLoc()) ==
       SM.getLineNumber(SwitchS->getRBraceLoc())) {
      OS << "\n";
   }
   auto Result = performCasesExpansionInSwitchStmt(SwitchS,
                                                   DiagEngine,
                                                   SwitchS->getStartLoc(),
                                                   OS);
   return Result;
}

static Expr *findLocalizeTarget(ResolvedCursorInfo CursorInfo) {
   if (CursorInfo.Kind != CursorInfoKind::ExprStart)
      return nullptr;
   struct StringLiteralFinder: public SourceEntityWalker {
      SourceLoc StartLoc;
      Expr *Target;
      StringLiteralFinder(SourceLoc StartLoc): StartLoc(StartLoc), Target(nullptr) {}
      bool walkToExprPre(Expr *E) {
         if (E->getStartLoc() != StartLoc)
            return false;
         if (E->getKind() == ExprKind::InterpolatedStringLiteral)
            return false;
         if (E->getKind() == ExprKind::StringLiteral) {
            Target = E;
            return false;
         }
         return true;
      }
   } Walker(CursorInfo.TrailingExpr->getStartLoc());
   Walker.walk(CursorInfo.TrailingExpr);
   return Walker.Target;
}

bool RefactoringActionLocalizeString::
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   return findLocalizeTarget(Tok);
}

bool RefactoringActionLocalizeString::performChange() {
   Expr* Target = findLocalizeTarget(CursorInfo);
   if (!Target)
      return true;
   EditConsumer.accept(SM, Target->getStartLoc(), "NSLocalizedString(");
   EditConsumer.insertAfter(SM, Target->getEndLoc(), ", comment: \"\")");
   return false;
}

struct MemberwiseParameter {
   Identifier Name;
   Type MemberType;
   Expr *DefaultExpr;

   MemberwiseParameter(Identifier name, Type type, Expr *initialExpr)
      : Name(name), MemberType(type), DefaultExpr(initialExpr) {}
};

static void generateMemberwiseInit(SourceEditConsumer &EditConsumer,
                                   SourceManager &SM,
                                   ArrayRef<MemberwiseParameter> memberVector,
                                   SourceLoc targetLocation) {

   assert(!memberVector.empty());

   EditConsumer.accept(SM, targetLocation, "\ninternal init(");
   auto insertMember = [&SM](const MemberwiseParameter &memberData,
                             llvm::raw_ostream &OS, bool wantsSeparator) {
      OS << memberData.Name << ": " << memberData.MemberType.getString();
      if (auto *expr = memberData.DefaultExpr) {
         if (isa<NilLiteralExpr>(expr)) {
            OS << " = nil";
         } else if (expr->getSourceRange().isValid()) {
            auto range =
               Lexer::getCharSourceRangeFromSourceRange(
                  SM, expr->getSourceRange());
            OS << " = " << SM.extractText(range);
         }
      }

      if (wantsSeparator) {
         OS << ", ";
      }
   };

   // Process the initial list of members, inserting commas as appropriate.
   std::string Buffer;
   llvm::raw_string_ostream OS(Buffer);
   for (const auto &memberData : memberVector.drop_back()) {
      insertMember(memberData, OS, /*wantsSeparator*/ true);
   }

   // Process the last (or perhaps, only) member.
   insertMember(memberVector.back(), OS, /*wantsSeparator*/ false);

   // Synthesize the body.
   OS << ") {\n";
   for (auto &member : memberVector) {
      // self.<property> = <property>
      OS << "self." << member.Name << " = " << member.Name << "\n";
   }
   OS << "}\n";

   // Accept the entire edit.
   EditConsumer.accept(SM, targetLocation, OS.str());
}

static SourceLoc
collectMembersForInit(ResolvedCursorInfo CursorInfo,
                      SmallVectorImpl<MemberwiseParameter> &memberVector) {

   if (!CursorInfo.ValueD)
      return SourceLoc();

   NominalTypeDecl *nominalDecl = dyn_cast<NominalTypeDecl>(CursorInfo.ValueD);
   if (!nominalDecl || nominalDecl->getStoredProperties().empty() ||
       CursorInfo.IsRef) {
      return SourceLoc();
   }

   SourceLoc bracesStart = nominalDecl->getBraces().start;
   if (!bracesStart.isValid())
      return SourceLoc();

   SourceLoc targetLocation = bracesStart.getAdvancedLoc(1);
   if (!targetLocation.isValid())
      return SourceLoc();

   for (auto varDecl : nominalDecl->getStoredProperties()) {
      auto patternBinding = varDecl->getParentPatternBinding();
      if (!patternBinding)
         continue;

      if (!varDecl->isMemberwiseInitialized(/*preferDeclaredProperties=*/true)) {
         continue;
      }

      const auto i = patternBinding->getPatternEntryIndexForVarDecl(varDecl);
      Expr *defaultInit = nullptr;
      if (patternBinding->isExplicitlyInitialized(i) ||
          patternBinding->isDefaultInitializable()) {
         defaultInit = varDecl->getParentInitializer();
      }

      memberVector.emplace_back(varDecl->getName(),
                                varDecl->getType(), defaultInit);
   }

   if (memberVector.empty()) {
      return SourceLoc();
   }

   return targetLocation;
}

bool RefactoringActionMemberwiseInitLocalRefactoring::
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {

   SmallVector<MemberwiseParameter, 8> memberVector;
   return collectMembersForInit(Tok, memberVector).isValid();
}

bool RefactoringActionMemberwiseInitLocalRefactoring::performChange() {

   SmallVector<MemberwiseParameter, 8> memberVector;
   SourceLoc targetLocation = collectMembersForInit(CursorInfo, memberVector);
   if (targetLocation.isInvalid())
      return true;

   generateMemberwiseInit(EditConsumer, SM, memberVector, targetLocation);

   return false;
}

static CharSourceRange
findSourceRangeToWrapInCatch(ResolvedCursorInfo CursorInfo,
                             SourceFile *TheFile,
                             SourceManager &SM) {
   Expr *E = CursorInfo.TrailingExpr;
   if (!E)
      return CharSourceRange();
   auto Node = AstNode(E);
   auto NodeChecker = [](AstNode N) { return N.isStmt(StmtKind::Brace); };
   ContextFinder Finder(*TheFile, Node, NodeChecker);
   Finder.resolve();
   auto Contexts = Finder.getContexts();
   if (Contexts.empty())
      return CharSourceRange();
   auto TargetNode = Contexts.back();
   BraceStmt *BStmt = dyn_cast<BraceStmt>(TargetNode.dyn_cast<Stmt*>());
   auto ConvertToCharRange = [&SM](SourceRange SR) {
      return Lexer::getCharSourceRangeFromSourceRange(SM, SR);
   };
   assert(BStmt);
   auto ExprRange = ConvertToCharRange(E->getSourceRange());
   // Check elements of the deepest BraceStmt, pick one that covers expression.
   for (auto Elem: BStmt->getElements()) {
      auto ElemRange = ConvertToCharRange(Elem.getSourceRange());
      if (ElemRange.contains(ExprRange))
         TargetNode = Elem;
   }
   return ConvertToCharRange(TargetNode.getSourceRange());
}

bool RefactoringActionConvertToDoCatch::
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   if (!Tok.TrailingExpr)
      return false;
   return isa<ForceTryExpr>(Tok.TrailingExpr);
}

bool RefactoringActionConvertToDoCatch::performChange() {
   auto *TryExpr = dyn_cast<ForceTryExpr>(CursorInfo.TrailingExpr);
   assert(TryExpr);
   auto Range = findSourceRangeToWrapInCatch(CursorInfo, TheFile, SM);
   if (!Range.isValid())
      return true;
   // Wrap given range in do catch block.
   EditConsumer.accept(SM, Range.getStart(), "do {\n");
   EditorConsumerInsertStream OS(EditConsumer, SM, Range.getEnd());
   OS << "\n} catch {\n" << getCodePlaceholder() << "\n}";

   // Delete ! from try! expression
   auto ExclaimLen = getKeywordLen(tok::exclaim_postfix);
   auto ExclaimRange = CharSourceRange(TryExpr->getExclaimLoc(), ExclaimLen);
   EditConsumer.remove(SM, ExclaimRange);
   return false;
}

/// Given a cursor position, this function tries to collect a number literal
/// expression immediately following the cursor.
static NumberLiteralExpr *getTrailingNumberLiteral(ResolvedCursorInfo Tok) {
   // This cursor must point to the start of an expression.
   if (Tok.Kind != CursorInfoKind::ExprStart)
      return nullptr;

   // For every sub-expression, try to find the literal expression that matches
   // our criteria.
   class FindLiteralNumber : public AstWalker {
      Expr * const parent;

   public:
      NumberLiteralExpr *found = nullptr;

      explicit FindLiteralNumber(Expr *parent) : parent(parent) { }

      std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
         if (auto *literal = dyn_cast<NumberLiteralExpr>(expr)) {
            // The sub-expression must have the same start loc with the outermost
            // expression, i.e. the cursor position.
            if (!found &&
                parent->getStartLoc().getOpaquePointerValue() ==
                expr->getStartLoc().getOpaquePointerValue()) {
               found = literal;
            }
         }

         return { found == nullptr, expr };
      }
   };

   auto parent = Tok.TrailingExpr;
   FindLiteralNumber finder(parent);
   parent->walk(finder);
   return finder.found;
}

static std::string insertUnderscore(StringRef Text) {
   llvm::SmallString<64> Buffer;
   llvm::raw_svector_ostream OS(Buffer);
   for (auto It = Text.begin(); It != Text.end(); It++) {
      unsigned Distance = It - Text.begin();
      if (Distance && !(Distance % 3)) {
         OS << '_';
      }
      OS << *It;
   }
   return OS.str().str();
}

static void insertUnderscoreInDigits(StringRef Digits,
                                     llvm::raw_ostream &OS) {
   std::string BeforePoint, AfterPoint;
   std::tie(BeforePoint, AfterPoint) = Digits.split('.');

   // Insert '_' for the part before the decimal point.
   std::reverse(BeforePoint.begin(), BeforePoint.end());
   BeforePoint = insertUnderscore(BeforePoint);
   std::reverse(BeforePoint.begin(), BeforePoint.end());
   OS << BeforePoint;

   // Insert '_' for the part after the decimal point, if necessary.
   if (!AfterPoint.empty()) {
      OS << '.';
      OS << insertUnderscore(AfterPoint);
   }
}

bool RefactoringActionSimplifyNumberLiteral::
isApplicable(ResolvedCursorInfo Tok, DiagnosticEngine &Diag) {
   if (auto *Literal = getTrailingNumberLiteral(Tok)) {
      llvm::SmallString<64> Buffer;
      llvm::raw_svector_ostream OS(Buffer);
      StringRef Digits = Literal->getDigitsText();
      insertUnderscoreInDigits(Digits, OS);

      // If inserting '_' results in a different digit sequence, this refactoring
      // is applicable.
      return OS.str() != Digits;
   }
   return false;
}

bool RefactoringActionSimplifyNumberLiteral::performChange() {
   if (auto *Literal = getTrailingNumberLiteral(CursorInfo)) {

      EditorConsumerInsertStream OS(EditConsumer, SM,
                                    CharSourceRange(SM, Literal->getDigitsLoc(),
                                                    Lexer::getLocForEndOfToken(SM,
                                                                               Literal->getEndLoc())));
      StringRef Digits = Literal->getDigitsText();
      insertUnderscoreInDigits(Digits, OS);
      return false;
   }
   return true;
}

static CallExpr *findTrailingClosureTarget(SourceManager &SM,
                                           ResolvedCursorInfo CursorInfo) {
   if (CursorInfo.Kind == CursorInfoKind::StmtStart)
      // StmtStart postion can't be a part of CallExpr.
      return nullptr;

   // Find inner most CallExpr
   ContextFinder
      Finder(*CursorInfo.SF, CursorInfo.Loc,
             [](AstNode N) {
                return N.isStmt(StmtKind::Brace) || N.isExpr(ExprKind::Call);
             });
   Finder.resolve();
   if (Finder.getContexts().empty()
       || !Finder.getContexts().back().is<Expr*>())
      return nullptr;
   CallExpr *CE = cast<CallExpr>(Finder.getContexts().back().get<Expr*>());

   if (CE->hasTrailingClosure())
      // Call expression already has a trailing closure.
      return nullptr;

   // The last arugment is a closure?
   Expr *Args = CE->getArg();
   if (!Args)
      return nullptr;
   Expr *LastArg;
   if (auto *PE = dyn_cast<ParenExpr>(Args)) {
      LastArg = PE->getSubExpr();
   } else {
      auto *TE = cast<TupleExpr>(Args);
      if (TE->getNumElements() == 0)
         return nullptr;
      LastArg = TE->getElements().back();
   }

   if (auto *ICE = dyn_cast<ImplicitConversionExpr>(LastArg))
      LastArg = ICE->getSyntacticSubExpr();

   if (isa<ClosureExpr>(LastArg) || isa<CaptureListExpr>(LastArg))
      return CE;
   return nullptr;
}

bool RefactoringActionTrailingClosure::
isApplicable(ResolvedCursorInfo CursorInfo, DiagnosticEngine &Diag) {
   SourceManager &SM = CursorInfo.SF->getAstContext().SourceMgr;
   return findTrailingClosureTarget(SM, CursorInfo);
}

bool RefactoringActionTrailingClosure::performChange() {
   auto *CE = findTrailingClosureTarget(SM, CursorInfo);
   if (!CE)
      return true;
   Expr *Arg = CE->getArg();

   Expr *ClosureArg = nullptr;
   Expr *PrevArg = nullptr;

   OriginalArgumentList ArgList = getOriginalArgumentList(Arg);

   auto NumArgs = ArgList.args.size();
   if (NumArgs == 0)
      return true;
   ClosureArg = ArgList.args[NumArgs - 1];
   if (NumArgs > 1)
      PrevArg = ArgList.args[NumArgs - 2];

   if (auto *ICE = dyn_cast<ImplicitConversionExpr>(ClosureArg))
      ClosureArg = ICE->getSyntacticSubExpr();

   if (ArgList.lParenLoc.isInvalid() || ArgList.rParenLoc.isInvalid())
      return true;

   // Replace:
   //   * Open paren with ' ' if the closure is sole argument.
   //   * Comma with ') ' otherwise.
   if (PrevArg) {
      CharSourceRange PreRange(
         SM,
         Lexer::getLocForEndOfToken(SM, PrevArg->getEndLoc()),
         ClosureArg->getStartLoc());
      EditConsumer.accept(SM, PreRange, ") ");
   } else {
      CharSourceRange PreRange(
         SM, ArgList.lParenLoc, ClosureArg->getStartLoc());
      EditConsumer.accept(SM, PreRange, " ");
   }
   // Remove original closing paren.
   CharSourceRange PostRange(
      SM,
      Lexer::getLocForEndOfToken(SM, ClosureArg->getEndLoc()),
      Lexer::getLocForEndOfToken(SM, ArgList.rParenLoc));
   EditConsumer.remove(SM, PostRange);
   return false;
}

static bool rangeStartMayNeedRename(ResolvedRangeInfo Info) {
   switch(Info.Kind) {
      case RangeKind::SingleExpression: {
         Expr *E = Info.ContainedNodes[0].get<Expr*>();
         // We should show rename for the selection of "foo()"
         if (auto *CE = dyn_cast<CallExpr>(E)) {
            if (CE->getFn()->getKind() == ExprKind::DeclRef)
               return true;

            // When callling an instance method inside another instance method,
            // we have a dot syntax call whose dot and base are both implicit. We
            // need to explicitly allow the specific case here.
            if (auto *DSC = dyn_cast<DotSyntaxCallExpr>(CE->getFn())) {
               if (DSC->getBase()->isImplicit() &&
                   DSC->getFn()->getStartLoc() == Info.TokensInRange.front().getLoc())
                  return true;
            }
         }
         return false;
      }
      case RangeKind::PartOfExpression: {
         if (auto *CE = dyn_cast<CallExpr>(Info.CommonExprParent)) {
            if (auto *DSC = dyn_cast<DotSyntaxCallExpr>(CE->getFn())) {
               if (DSC->getFn()->getStartLoc() == Info.TokensInRange.front().getLoc())
                  return true;
            }
         }
         return false;
      }
      case RangeKind::SingleDecl:
      case RangeKind::MultiTypeMemberDecl:
      case RangeKind::SingleStatement:
      case RangeKind::MultiStatement:
      case RangeKind::Invalid:
         return false;
   }
   llvm_unreachable("unhandled kind");
}
}// end of anonymous namespace

StringRef polar::ide::
getDescriptiveRefactoringKindName(RefactoringKind Kind) {
   switch(Kind) {
      case RefactoringKind::None:
         llvm_unreachable("Should be a valid refactoring kind");
#define REFACTORING(KIND, NAME, ID) case RefactoringKind::KIND: return NAME;
#include "polarphp/ide/RefactoringKindsDef.h"
   }
   llvm_unreachable("unhandled kind");
}

StringRef polar::ide::
getDescriptiveRenameUnavailableReason(RenameAvailableKind Kind) {
   switch(Kind) {
      case RenameAvailableKind::Available:
         return "";
      case RenameAvailableKind::Unavailable_system_symbol:
         return "symbol from system module cannot be renamed";
      case RenameAvailableKind::Unavailable_has_no_location:
         return "symbol without a declaration location cannot be renamed";
      case RenameAvailableKind::Unavailable_has_no_name:
         return "cannot find the name of the symbol";
      case RenameAvailableKind::Unavailable_has_no_accessibility:
         return "cannot decide the accessibility of the symbol";
      case RenameAvailableKind::Unavailable_decl_from_clang:
         return "cannot rename a Clang symbol from its Swift reference";
   }
   llvm_unreachable("unhandled kind");
}

SourceLoc polar::ide::RangeConfig::getStart(SourceManager &SM) {
   return SM.getLocForLineCol(BufferId, Line, Column);
}

SourceLoc polar::ide::RangeConfig::getEnd(SourceManager &SM) {
   return getStart(SM).getAdvancedLoc(Length);
}

struct polar::ide::FindRenameRangesAnnotatingConsumer::Implementation {
   std::unique_ptr<SourceEditConsumer> pRewriter;
   Implementation(SourceManager &SM, unsigned BufferId, llvm::raw_ostream &OS)
      : pRewriter(new SourceEditOutputConsumer(SM, BufferId, OS)) {}
   static StringRef tag(RefactoringRangeKind Kind) {
      switch (Kind) {
         case RefactoringRangeKind::BaseName:
            return "base";
         case RefactoringRangeKind::KeywordBaseName:
            return "keywordBase";
         case RefactoringRangeKind::ParameterName:
            return "param";
         case RefactoringRangeKind::NoncollapsibleParameterName:
            return "noncollapsibleparam";
         case RefactoringRangeKind::DeclArgumentLabel:
            return "arglabel";
         case RefactoringRangeKind::CallArgumentLabel:
            return "callarg";
         case RefactoringRangeKind::CallArgumentColon:
            return "callcolon";
         case RefactoringRangeKind::CallArgumentCombined:
            return "callcombo";
         case RefactoringRangeKind::SelectorArgumentLabel:
            return "sel";
      }
      llvm_unreachable("unhandled kind");
   }
   void accept(SourceManager &SM, const RenameRangeDetail &Range) {
      std::string NewText;
      llvm::raw_string_ostream OS(NewText);
      StringRef Tag = tag(Range.RangeKind);
      OS << "<" << Tag;
      if (Range.Index.hasValue())
         OS << " index=" << *Range.Index;
      OS << ">" << Range.Range.str() << "</" << Tag << ">";
      pRewriter->accept(SM, {Range.Range, OS.str(), {}});
   }
};

polar::ide::FindRenameRangesAnnotatingConsumer::
FindRenameRangesAnnotatingConsumer(SourceManager &SM, unsigned BufferId,
                                   llvm::raw_ostream &OS): Impl(*new Implementation(SM, BufferId, OS)) {}

polar::ide::FindRenameRangesAnnotatingConsumer::~FindRenameRangesAnnotatingConsumer() {
   delete &Impl;
}

void polar::ide::FindRenameRangesAnnotatingConsumer::
accept(SourceManager &SM, RegionType RegionType,
       ArrayRef<RenameRangeDetail> Ranges) {
   if (RegionType == RegionType::Mismatch || RegionType == RegionType::Unmatched)
      return;
   for (const auto &Range : Ranges) {
      Impl.accept(SM, Range);
   }
}
ArrayRef<RenameAvailabiliyInfo>
polar::ide::collectRenameAvailabilityInfo(const ValueDecl *VD,
                                          std::vector<RenameAvailabiliyInfo> &Scratch) {
   RenameAvailableKind AvailKind = RenameAvailableKind::Available;
   if (getRelatedSystemDecl(VD)){
      AvailKind = RenameAvailableKind::Unavailable_system_symbol;
   } else if (VD->getClangDecl()) {
      AvailKind = RenameAvailableKind::Unavailable_decl_from_clang;
   } else if (VD->getStartLoc().isInvalid()) {
      AvailKind = RenameAvailableKind::Unavailable_has_no_location;
   } else if (!VD->hasName()) {
      AvailKind = RenameAvailableKind::Unavailable_has_no_name;
   }

   if (isa<AbstractFunctionDecl>(VD)) {
      // Disallow renaming accessors.
      if (isa<AccessorDecl>(VD))
         return Scratch;

      // Disallow renaming deinit.
      if (isa<DestructorDecl>(VD))
         return Scratch;

      // Disallow renaming init with no arguments.
      if (auto CD = dyn_cast<ConstructorDecl>(VD)) {
         if (!CD->getParameters()->size())
            return Scratch;
      }
   }

   // Always return local rename for parameters.
   // FIXME: if the cursor is on the argument, we should return global rename.
   if (isa<ParamDecl>(VD)) {
      Scratch.emplace_back(RefactoringKind::LocalRename, AvailKind);
      return Scratch;
   }

   // If the indexer considers VD a global symbol, then we apply global rename.
   if (index::isLocalSymbol(VD))
      Scratch.emplace_back(RefactoringKind::LocalRename, AvailKind);
   else
      Scratch.emplace_back(RefactoringKind::GlobalRename, AvailKind);

   return llvm::makeArrayRef(Scratch);
}

ArrayRef<RefactoringKind> polar::ide::
collectAvailableRefactorings(SourceFile *SF,
                             ResolvedCursorInfo CursorInfo,
                             std::vector<RefactoringKind> &Scratch,
                             bool ExcludeRename) {
   llvm::SmallVector<RefactoringKind, 2> AllKinds;
   switch(CursorInfo.Kind) {
      case CursorInfoKind::ModuleRef:
      case CursorInfoKind::Invalid:
      case CursorInfoKind::StmtStart:
      case CursorInfoKind::ExprStart:
         break;
      case CursorInfoKind::ValueRef: {
         auto RenameOp = getAvailableRenameForDecl(CursorInfo.ValueD);
         if (RenameOp.hasValue() &&
             RenameOp.getValue() == RefactoringKind::GlobalRename)
            AllKinds.push_back(RenameOp.getValue());
      }
   }
   DiagnosticEngine DiagEngine(SF->getAstContext().SourceMgr);
#define CURSOR_REFACTORING(KIND, NAME, ID)                                     \
  if (RefactoringAction##KIND::isApplicable(CursorInfo, DiagEngine))           \
    AllKinds.push_back(RefactoringKind::KIND);
#include "polarphp/ide/RefactoringKindsDef.h"

   // Exclude renames.
   for(auto Kind: AllKinds) {
      switch (Kind) {
         case RefactoringKind::LocalRename:
         case RefactoringKind::GlobalRename:
            if (ExcludeRename)
               break;
            LLVM_FALLTHROUGH;
         default:
            Scratch.push_back(Kind);
      }
   }

   return llvm::makeArrayRef(Scratch);
}



ArrayRef<RefactoringKind> polar::ide::
collectAvailableRefactorings(SourceFile *SF, RangeConfig Range,
                             bool &RangeStartMayNeedRename,
                             std::vector<RefactoringKind> &Scratch,
                             llvm::ArrayRef<DiagnosticConsumer*> DiagConsumers) {

   if (Range.Length == 0) {
      return collectAvailableRefactoringsAtCursor(SF, Range.Line, Range.Column,
                                                  Scratch, DiagConsumers);
   }
   // Prepare the tool box.
   AstContext &Ctx = SF->getAstContext();
   SourceManager &SM = Ctx.SourceMgr;
   DiagnosticEngine DiagEngine(SM);
   std::for_each(DiagConsumers.begin(), DiagConsumers.end(),
                 [&](DiagnosticConsumer *Con) { DiagEngine.addConsumer(*Con); });
   ResolvedRangeInfo Result = evaluateOrDefault(SF->getAstContext().evaluator,
                                                RangeInfoRequest(RangeInfoOwner({SF,
                                                                                 Range.getStart(SF->getAstContext().SourceMgr),
                                                                                 Range.getEnd(SF->getAstContext().SourceMgr)})),
                                                ResolvedRangeInfo());

   bool enableInternalRefactoring = getenv("SWIFT_ENABLE_INTERNAL_REFACTORING_ACTIONS");

#define RANGE_REFACTORING(KIND, NAME, ID)                                     \
  if (RefactoringAction##KIND::isApplicable(Result, DiagEngine))              \
    Scratch.push_back(RefactoringKind::KIND);
#define INTERNAL_RANGE_REFACTORING(KIND, NAME, ID)                            \
  if (enableInternalRefactoring)                                              \
    RANGE_REFACTORING(KIND, NAME, ID)
#include "polarphp/ide/RefactoringKindsDef.h"

   RangeStartMayNeedRename = rangeStartMayNeedRename(Result);
   return Scratch;
}

bool polar::ide::
refactorSwiftModule(ModuleDecl *M, RefactoringOptions Opts,
                    SourceEditConsumer &EditConsumer,
                    DiagnosticConsumer &DiagConsumer) {
   assert(Opts.Kind != RefactoringKind::None && "should have a refactoring kind.");

   // Use the default name if not specified.
   if (Opts.PreferredName.empty()) {
      Opts.PreferredName = getDefaultPreferredName(Opts.Kind);
   }

   switch (Opts.Kind) {
#define SEMANTIC_REFACTORING(KIND, NAME, ID)                                   \
case RefactoringKind::KIND: {                                                  \
      RefactoringAction##KIND Action(M, Opts, EditConsumer, DiagConsumer);     \
      if (RefactoringKind::KIND == RefactoringKind::LocalRename ||             \
          Action.isApplicable())                                               \
        return Action.performChange();                                         \
      return true;                                                             \
  }
#include "polarphp/ide/RefactoringKindsDef.h"
      case RefactoringKind::GlobalRename:
      case RefactoringKind::FindGlobalRenameRanges:
      case RefactoringKind::FindLocalRenameRanges:
         llvm_unreachable("not a valid refactoring kind");
      case RefactoringKind::None:
         llvm_unreachable("should not enter here.");
   }
   llvm_unreachable("unhandled kind");
}

static std::vector<ResolvedLoc>
resolveRenameLocations(ArrayRef<RenameLoc> RenameLocs, SourceFile &SF,
                       DiagnosticEngine &Diags) {
   SourceManager &SM = SF.getAstContext().SourceMgr;
   unsigned BufferID = SF.getBufferID().getValue();

   std::vector<UnresolvedLoc> UnresolvedLocs;
   for (const RenameLoc &RenameLoc : RenameLocs) {
      DeclNameViewer OldName(RenameLoc.OldName);
      SourceLoc Location = SM.getLocForLineCol(BufferID, RenameLoc.Line,
                                               RenameLoc.Column);

      if (!OldName.isValid()) {
         Diags.diagnose(Location, diag::invalid_name, RenameLoc.OldName);
         return {};
      }

      if (!RenameLoc.NewName.empty()) {
         DeclNameViewer NewName(RenameLoc.NewName);
         ArrayRef<StringRef> ParamNames = NewName.args();
         bool newOperator = Lexer::isOperator(NewName.base());
         bool NewNameIsValid = NewName.isValid() &&
                               (Lexer::isIdentifier(NewName.base()) || newOperator) &&
                               std::all_of(ParamNames.begin(), ParamNames.end(), [](StringRef Label) {
                                  return Label.empty() || Lexer::isIdentifier(Label);
                               });

         if (!NewNameIsValid) {
            Diags.diagnose(Location, diag::invalid_name, RenameLoc.NewName);
            return {};
         }

         if (NewName.partsCount() != OldName.partsCount()) {
            Diags.diagnose(Location, diag::arity_mismatch, RenameLoc.NewName,
                           RenameLoc.OldName);
            return {};
         }

         if (RenameLoc.Usage == NameUsage::Call && !RenameLoc.IsFunctionLike) {
            Diags.diagnose(Location, diag::name_not_functionlike, RenameLoc.NewName);
            return {};
         }
      }

      bool isOperator = Lexer::isOperator(OldName.base());
      UnresolvedLocs.push_back({
                                  Location,
                                  (RenameLoc.Usage == NameUsage::Unknown ||
                                   (RenameLoc.Usage == NameUsage::Call && !isOperator))
                               });
   }

   NameMatcher Resolver(SF);
   return Resolver.resolve(UnresolvedLocs, SF.getAllTokens());
}

int polar::ide::syntacticRename(SourceFile *SF, ArrayRef<RenameLoc> RenameLocs,
                                SourceEditConsumer &EditConsumer,
                                DiagnosticConsumer &DiagConsumer) {

   assert(SF && "null source file");

   SourceManager &SM = SF->getAstContext().SourceMgr;
   DiagnosticEngine DiagEngine(SM);
   DiagEngine.addConsumer(DiagConsumer);

   auto ResolvedLocs = resolveRenameLocations(RenameLocs, *SF, DiagEngine);
   if (ResolvedLocs.size() != RenameLocs.size())
      return true; // Already diagnosed.

   size_t index = 0;
   llvm::StringSet<> ReplaceTextContext;
   for(const RenameLoc &Rename: RenameLocs) {
      ResolvedLoc &Resolved = ResolvedLocs[index++];
      TextReplacementsRenamer Renamer(SM, Rename.OldName, Rename.NewName,
                                      ReplaceTextContext);
      RegionType Type = Renamer.addSyntacticRenameRanges(Resolved, Rename);
      if (Type == RegionType::Mismatch) {
         DiagEngine.diagnose(Resolved.Range.getStart(), diag::mismatched_rename,
                             Rename.NewName);
         EditConsumer.accept(SM, Type, None);
      } else {
         EditConsumer.accept(SM, Type, Renamer.getReplacements());
      }
   }

   return false;
}

int polar::ide::findSyntacticRenameRanges(
   SourceFile *SF, llvm::ArrayRef<RenameLoc> RenameLocs,
   FindRenameRangesConsumer &RenameConsumer,
   DiagnosticConsumer &DiagConsumer) {
   assert(SF && "null source file");

   SourceManager &SM = SF->getAstContext().SourceMgr;
   DiagnosticEngine DiagEngine(SM);
   DiagEngine.addConsumer(DiagConsumer);

   auto ResolvedLocs = resolveRenameLocations(RenameLocs, *SF, DiagEngine);
   if (ResolvedLocs.size() != RenameLocs.size())
      return true; // Already diagnosed.

   size_t index = 0;
   for (const RenameLoc &Rename : RenameLocs) {
      ResolvedLoc &Resolved = ResolvedLocs[index++];
      RenameRangeDetailCollector Renamer(SM, Rename.OldName);
      RegionType Type = Renamer.addSyntacticRenameRanges(Resolved, Rename);
      if (Type == RegionType::Mismatch) {
         DiagEngine.diagnose(Resolved.Range.getStart(), diag::mismatched_rename,
                             Rename.NewName);
         RenameConsumer.accept(SM, Type, None);
      } else {
         RenameConsumer.accept(SM, Type, Renamer.Ranges);
      }
   }

   return false;
}

int polar::ide::findLocalRenameRanges(
   SourceFile *SF, RangeConfig Range,
   FindRenameRangesConsumer &RenameConsumer,
   DiagnosticConsumer &DiagConsumer) {
   assert(SF && "null source file");

   SourceManager &SM = SF->getAstContext().SourceMgr;
   DiagnosticEngine Diags(SM);
   Diags.addConsumer(DiagConsumer);

   auto StartLoc = Lexer::getLocForStartOfToken(SM, Range.getStart(SM));
   ResolvedCursorInfo CursorInfo =
      evaluateOrDefault(SF->getAstContext().evaluator,
                        CursorInfoRequest{CursorInfoOwner(SF, StartLoc)},
                        ResolvedCursorInfo());
   if (!CursorInfo.isValid() || !CursorInfo.ValueD) {
      Diags.diagnose(StartLoc, diag::unresolved_location);
      return true;
   }
   ValueDecl *VD = CursorInfo.CtorTyRef ? CursorInfo.CtorTyRef : CursorInfo.ValueD;
   llvm::SmallVector<DeclContext *, 8> Scopes;
   analyzeRenameScope(VD, Diags, Scopes);
   if (Scopes.empty())
      return true;
   RenameRangeCollector RangeCollector(VD, StringRef());
   for (DeclContext *DC : Scopes)
      indexDeclContext(DC, RangeCollector);

   return findSyntacticRenameRanges(SF, RangeCollector.results(), RenameConsumer,
                                    DiagConsumer);
}
